file upload with spring MVC - java

I am uploading file using spring MVC and jquery. Inside my class method I have written
#RequestMapping(value="attachFile", method=RequestMethod.POST)
public #ResponseBody List<FileAttachment> upload(
#RequestParam("file") MultipartFile file,
HttpServletRequest request,
HttpSession session) {
String fileName = null;
InputStream inputStream = null;
OutputStream outputStream = null;
//Save the file to a temporary location
ServletContext context = session.getServletContext();
String realContextPath = context.getRealPath("/");
fileName = realContextPath +"/images/"+file.getOriginalFilename();
//File dest = new File(fileName);
try {
//file.transferTo(dest);
inputStream = file.getInputStream();
outputStream = new FileOutputStream(fileName);
inputStream.close();
outputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Its uploading the file correctly I am using
ServletContext context = session.getServletContext();
String realContextPath = context.getRealPath("/");
to get the path. My first question is , Is this the correct way to get the path and it stores the file somewhere at
workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/myproject/images
and when I am trying to display this image on my jsp page using the following code
<img src="<%=request.getRealPath("/") + "images/images.jpg" %>" alt="Upload Image" />
It does not display the image, Its generating the following html
<img src="/home/name/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/myproject/images/images.jpg" alt="Upload Image">
Am I doing the things right? In my project I have to upload large number of files everyday.
Please let me know if you need anything else to understand my question

It will be better if you upload your files in some directory by absolute path(e.g. C:\images\) instead of relative (your approach). Usually, web apps runs on linux mathines on production and it is good practice to make save path configurable.
Create some application property which will holds save path for files(in xml or property file).

Related

How to download a file from Google Cloud Storage and return it in Spring controller

I have a Spring Boot application.
Users can login to my application and upload files.
All the files of users are stored in a Google Cloud Storage.
Now, I want the users to be able to download their files.
So, I have to download the files form the Cloud Storage.
I don't know how my controller should look.
With my current code I'm getting an empty file. The upload is already made and the connection is fine as well.
public static Blob downloadFile(Storage storage, String fileName){
Blob blob = storage.get(BUCKET_NAME, fileName);
return blob;
}
#RequestMapping(value = "/downloadFileTest")
#ResponseBody
public void downloadFile(HttpSession session,
HttpServletResponse response) {
Storage storage = de.msm.msmcenter.service.cloudstorage.Authentication.getStorage();
Blob blob = de.msm.msmcenter.service.cloudstorage.Authentication.downloadFile(storage,"test.txt");
ReadChannel readChannel = blob.reader();
InputStream inputStream = Channels.newInputStream(readChannel);
try {
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment; filename=test.txt");
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
inputStream.close();
} catch (Exception e){
e.printStackTrace();
}
}
I actually want to be able to download any file, not only txt.
When the user opens the link, the file with the name test.txt gets downloaded but it's empty..
It seems like you just want to give access to the user to be able to download the file.
A solution for that would be to use a Signed URL, which can let you provide the user with an URL to access/download the object for a limited time. If you redirect the user directly to that URL the download would start immediately.
Thank you #Mayeru
I changed my code to :
public static String downloadFile(Storage storage, String fileName){
Blob blob = storage.get(BUCKET_NAME, fileName);
String PATH_TO_JSON_KEY = "/your/path";
URL signedUrl = null;
try {
signedUrl = storage.signUrl(BlobInfo.newBuilder(BUCKET_NAME, fileName).build(),
1, TimeUnit.DAYS, SignUrlOption.signWith(ServiceAccountCredentials.fromStream(
new FileInputStream(PATH_TO_JSON_KEY))));
} catch (IOException e) {
e.printStackTrace();
}
return signedUrl.toString();
}
#add this line to you spring-boot application.properties file
spring.cloud.gcp.credentials.location=classpath:key.json
// read/download objects
public static ResponseEntity<byte[]> getObjectFromGCP(String yourfileName) throws IOException {
String objectNameWithLocation ="your file location with file name in GCP bucket";
//create your storage object with your credentials
Credentials credentials = GoogleCredentials.fromStream(new
ClassPathResource("key.json").getInputStream());
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();
BlobId blobId = BlobId.of(bucketName, objectNameWithLocation);
Blob blob = storage.get(blobId);
return ResponseEntity.ok().contentType(MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(yourfileName)))
.body(blob.getContent(BlobSourceOption.generationMatch()));
}

Generating pdf with wkhtmltopdf and download the pdf

I am working in a old project.The project is in Spring MVC .In the project I have to generate a pdf file from a jsp page and store in a location and download that file. For that I am using wkhtmltopdf tool to convert the one specific jsp page into pdf format. Using wkhtmltopdf sometime works fine, it generate the pdf in specific location, but sometime it require more time. Also when I am trying to download the file from specific location , sometime it download a 0KB size file or sometime the downloaded file can't be open (with some size) but sometime download perfectly. If I check the file at define location, it exist and open normally.
Here is my code in controller class.
#RequestMapping(value="/dwn.htm",method=RequestMethod.GET)
public void dwAppFm(HttpSession session,HttpServletRequest request,HttpServletResponse response,#RequestParam String id) throws IOException,InterruptedException
{
final int BUFFER_SIZES=4096;
ServletContext context=request.getServletContext();
String savePath="/tmp/";//PDF file Generate Path
String fileName="PDFFileName"; //Pdf file name
FileInputStream inputStream=null;
BufferedInputStream bufferedInputStream=null;
OutputStream outputStream=null;
printApp(id,fileName);
Thread.sleep(1000);
printApp(id,fileName);
File download=new File(savePath+fileName+".pdf");
while(!download.canRead())
{
Thread.sleep(1000);
printApp(id,fileName);
download=new File(savePath+fileName+".pdf");
}
if(download.canRead()){//if the file can read
try{
Thread.sleep(1000);
inputStream=new FileInputStream(download);
bufferedInputStream=new BufferedInputStream(inputStream);
String mimeType = context.getMimeType(savePath+fileName+".pdf");
if (mimeType == null) {
mimeType = "application/octet-stream";
}
System.out.println("MIME type: " + mimeType);
response.setContentType(mimeType);
response.setContentLength((int)download.length());
String headerKey="Content-Disposition";
String headerValue=String.format("attachment;filename=\"%s\"", download.getName());
response.setHeader(headerKey, headerValue);
outputStream=response.getOutputStream();
byte[] buffer=new byte[BUFFER_SIZES];
int bytesRead=-1;
while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}catch(Exception e)
{
e.printStackTrace();
}
finally
{
try{
if(inputStream!=null)inputStream.close();
if(bufferedInputStream!=null)bufferedInputStream.close();
if(outputStream!=null)outputStream.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
public void printApp(String id,String fileName)
{
try{
String urlPath="http://localhost:8080/proj";
urlPath+="/genApp.htm?id="+id;//generate url to execute wkhtmltopdf
String wxpath="/home/exm/wkhtmltopdf";//the path where wkhtmltopdf located
String save="/tmp/"+fileName+".pdf";//File save Pathname
Process process=null;
process=Runtime.getRuntime().exec(wxpath+" "+urlPath+" "+save);
}catch(Exception e)
{}
}
#RequestMapping(value="/genApp.htm",method=RequestMethod.GET)
public String getApplicationPDF(HttpServletRequest request,HttpSession session,#RequestParam String id)
{
UDets uDets=uService.getAllById(Long.parseLong(id));//Methods to get details
request.setAttribute("uDets",uDets );
return "makeApp";//Name of the jsp page
}
In my code I have use Thread.sleep(1000) and printApp(id,fileName) method three times , since sometime wkhtmltopdf fail to generate pdf in certain time and then probability of downloading 0KB file is more. I haven't share the jsp page since the jsp page contain simple jsp page code of lots of line (the size of the generated pdf file is two page).
So the problem is what should I change in my code so that the pdf file generated and download without a failure also in heavy load in server.
If there is any best procedure or idea please share.
I don't like to use itext, since the jsp page contain complex design. Any advise is also appreciable and also thanks in advance.
I would say that your code is flawed not just a little but big time. You are checking if a file can be read, if not you start again a proces writing to the same file (at least twice). At some time you will endup with multiple processes trying to write to the same file, resulting in strange behavior.
I would refactor the printApp method to return the Process it created. Then call waitFor on that process. If it returns 0 and doesn't get interrupted it completed successfully and you should be able to download the file.
#RequestMapping(value="/dwn.htm",method=RequestMethod.GET)
public void dwAppFm(HttpSession session,HttpServletRequest request,HttpServletResponse response,#RequestParam String id) throws IOException,InterruptedException
{
String savePath="/tmp/";//PDF file Generate Path
String fileName="PDFFileName.pdf"; //Pdf file name
File download = new File(savePath, fileName);
try {
Process process = printApp(id, download.getPath());
int status = process.waitFor();
if (status == 0) {
response.setContentType("application/pdf");
response.setContentLength((int)download.length());
String headerKey="Content-Disposition";
String headerValue=String.format("attachment;filename=\"%s\"", download.getName());
StreamUtils.copy(new FileInputStream(download), response.getOutputStream())
} else {
// do something if it fails.
}
} catch (IOException ioe) {
// Do something to handle exception
} catch (InterruptedException ie) {
// Do something to handle exception
}
}
}
public Process printApp(String id, String pdf) throws IOException {
String urlPath="http://localhost:8080/proj";
urlPath+="/genApp.htm?id="+id;//generate url to execute wkhtmltopdf
String wxpath="/home/exm/wkhtmltopdf";//the path where wkhtmltopdf located
String command = wxpath+" "+urlPath+" "+pdf;
return Runtime.getRuntime().exec(command);
}
Something like the code above should to the trick.

Primefaces Download File Which is Outside FacesContext

I'm uploading an Excel Workbook to a directory which is outside the application context (for backup purposes) and saving its path into the database.
Now I need to download that file and I'm trying to use Primefaces Download, but I'm getting a null file.
Here is my code (much like Primefaces Showcase Download section):
Bean:
private StreamedContent file;
public void download(Arquivo arquivo) throws IOException {
InputStream stream = ((ServletContext)FacesContext.getCurrentInstance()
.getExternalContext().getContext()).getResourceAsStream(arquivo.getNomeArquivo());
file = new DefaultStreamedContent(stream);
}
View:
<h:commandLink id="btnDownload" title="Download Arquivo"
actionListener="#{arquivoBean.download(obj)}">
<p:fileDownload value="#{arquivoBean.file}" />
</h:commandLink>
Basically I need to pass an external path to InputStream instead of FacesContext.
From what I see my problem is that I'm passing my application context to the InputStream, appending the path in the argument of getResourceAsStream which, of course, is not found.
I'm new to this FileDownload thing. Thanks in advance!
If it can still be useful :
StreamedContent streamToReturn = DefaultStreamedContent.builder().name(FILE_NAME).contentType( FacesContext.getCurrentInstance().getExternalContext()
.getMimeType(FILE_PATH))
.stream(() -> {
try {
return new FileInputStream(FILE_PATH);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}).build();

Rendering generated png into JSF

I built an image form PDF doc inside a JSF backing bean, i need to show image inside JSF page. I found that primefaces has a component named , I defined a variable:
private StreamedContent pdfImage;
according to this example http://www.primefaces.org/showcase/ui/dynamicImage.jsf. In my code
i built pdf using some data and apache PDFBox and save document into:
private byte[] bytesPdf;
My jsf line is
<p:graphicImage value="#{myBean.pdfImage}" rendered="#{myBean.showImage}"/>
After that i call following method that tranform first PDF document page to PNG i get:
public void buildPDFImage() throws IOException{
ByteArrayOutputStream os = new ByteArrayOutputStream();
//Build bufferedImage from pdf bytearray
InputStream input = new ByteArrayInputStream(bytesPdf);
PDDocument archivo=new PDDocument();
archivo=PDDocument.load(input);
PDPage firstPage = (PDPage) archivo.getDocumentCatalog().getAllPages().get(0);
BufferedImage bufferedImage = firstPage.convertToImage();
//File exit=new File("d:/exit.png"); if i do something like this and pass file as param to iowrite image is generated on file system
try {
ImageIO.write(bufferedImage, "png", os);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pdfImage = new DefaultStreamedContent(new ByteArrayInputStream(os.toByteArray()), "image/png");
}
When i run my app after generate pdf image i get this trace
GRAVE: Error Rendering View[/pages/apphuella.xhtml]
java.lang.IllegalStateException: PWC3999: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:2880)
at org.apache.catalina.connector.Request.getSession(Request.java:2577)
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:920)
at com.sun.faces.context.SessionMap.getSession(SessionMap.java:235)
at com.sun.faces.context.SessionMap.put(SessionMap.java:126)
at com.sun.faces.context.SessionMap.put(SessionMap.java:61)
at org.primefaces.component.graphicimage.GraphicImageRenderer.getImageSrc(GraphicImageRenderer.java:105)
at org.primefaces.component.graphicimage.GraphicImageRenderer.encodeEnd(GraphicImageRenderer.java:45)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1763)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1756)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1759)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1759)
at
I would know if i´m using correctly if don´t how could i use it to show generated png(and other images)?, also if there´s other option to show runtime generated images on JSF pages.
Thanks in advance
At first, you need to keep the file a temporary directory. After that you should render the file again.
Try as below
Backing Bean
private String filePath;
public String filePath() {
return filePath;
}
private String getSystemPath() {
Object context = getFacesContext().getExternalContext().getContext();
String systemPath = ((ServletContext)context).getRealPath("/");
return systemPath;
}
public void buildPDFImage() throws IOException {
// create any kind of file types.
byte[] cotent = --> take byte array content of your files.
Stirng fileName = "xxx.pdf" or "xxx.png" --> your file name
String dirPath = "/pdf/" or "/images/"; --> a directory to place created files.
filePath = dirPath + fileName
createFile(new File(getSystemPath() + filePath), content);
}
private void createFile(File file, byte[] content) {
try {
/*At First : Create directory of target file*/
String filePath = file.getPath();
int lastIndex = filePath.lastIndexOf("\\") + 1;
FileUtils.forceMkdir(new File(filePath.substring(0, lastIndex)));
/*Create target file*/
FileOutputStream outputStream = new FileOutputStream(file);
IOUtils.write(content, outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Pages
<h:form enctype="multipart/form-data">
<h:commandButton value="Create"/>
<!-- Your Files is image -->
<p:graphicImage value="#{myBean.filePath}"/>
<!--
Your Files is pdf. You need PDF Viewer plugin for your browser.
My FireFox vesion is 20.0. It have default PDF Viewer.
If PDF File cannot display on your browser, it is depond on browser setting also.
-->
<p:media value="#{myBean.filePath}" width="100%" height="300px"/>
</h:form>

open a file in a tomcat webapplication

i want to open a file and return its content. Although it is in the same directory like the class that wants to open the file, the file can't be found. Would be cool if you could help me solving the problem.
Here is the code:
#GET #Produces("text/html") #Path("/{partNO}/") #Consumes("text/html")
public String getPartNoResponseHTML(#PathParam("partNO") String parID) throws WebApplicationException {
PartNoTemplate partNo = getPartNoResponse(parID);
String result = "";
try {
result = readFile(PART_NO_TEMPLATE_FILE);
} catch (FileNotFoundException e) {
e.printStackTrace(System.out);
return e.getMessage() + e.toString();
// throw new WebApplicationException(Response.Status.NOT_FOUND);
} finally {
result = result.replace("{partNO}", parID);
result = result.replace("{inputFormat}", partNo.getFormat().toString());
}
return result;
}
I guess it can't find the file, because its running on tomcat. I'm also using Jersey and JAX-RS. Thank you for your help,
Maxi
If the file is inside the application WAR (or in a jar) you can try by using
InputStream input = servletContext.getClass().getClassLoader().getResourceAsStream("my_filename.txt");
Your problem is similar (I think) with How can I read file from classes directory in my WAR?
Try to get the path of the file from ServletContext.
ServletContext context = //Get the servlet context
In JAX-RS to get servlet context use this:
#javax.ws.rs.core.Context
ServletContext context;
Then get the file from your web application:
File file = new File(context.getRealPath("/someFolder/myFile.txt"));
You don't post the code that actually tries to read the file, but assuming the file is in the classpath (as you mention it's in the same directory as the class) then you can do:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
See here

Categories