I'm working on a standalone app where results are exported in an excel sheet. I use Jxls for the export. All is working in Eclipse, but the exported jar just gives me a non-working sheet. Is it a problem with the output stream that doesn't write anything, or is it something with the absolute path? I'm a bit confused here.
The export is made with the required libraries packed in the jar.
The code of the exporting part :
private void exportDataDet(File file) throws ParseException, IOException, ParsePropertyException, InvalidFormatException {
String path = System.getProperty("user.home") + File.separator + "tempFile";
File IdGenreXLS = new File(path + ".xlsx");
List<ResultsDetails> detRes = generateResultsDetails();
try(InputStream is = IdGenre.class.getResourceAsStream("/xlsTemplates/IdGenre/IdGenre_20-29-et=12.xlsx")) {
try (OutputStream os = new FileOutputStream(IdGenreXLS)) {
Context context = new Context();
context.putVar("detRes", detRes);
JxlsHelper.getInstance().processTemplate(is, os, context);
}
}
Thanks for any suggestion.
Alright, the hypothesis that nothing was written on disk was the good one, as eventually nothing was written on disk.
A simple
os.flush();
at the end makes everything working. There's nothing for it but to close the input and output stream after.
Related
I have deployed a spring-boot application JAR file. Now, I want to upload the image from android and store it in the myfolder of resource directory. But unable to get the path of resource directory.
Error is:
java.io.FileNotFoundException: src/main/resources/static/myfolder/myimage.png
(No such file or directory)
This is the code for storing the file in the resource folder
private final String RESOURCE_PATH = "src/main/resources";
String filepath = "/myfolder/";
public String saveFile(byte[] bytes, String filepath, String filename) throws MalformedURLException, IOException {
File file = new File(RESOURCE_PATH + filepath + filename);
OutputStream out = new FileOutputStream(file);
try {
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
return file.getName();
}
UPDATED:
This is what I have tried
private final String RESOURCE_PATH = "config/";
controller class:
String filepath = "myfolder/";
String filename = "newfile.png"
public String saveFile(byte[] bytes, String filepath, String filename) throws MalformedURLException, IOException {
//reading old file
System.out.println(Files.readAllBytes(Paths.get("config","myfolder","oldfile.png"))); //gives noSuchFileException
//writing new file
File file = new File(RESOURCE_PATH + filepath + filename);
OutputStream out = new FileOutputStream(file); //FileNotFoundException
try {
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
return file.getName();
}
Project structure:
+springdemo-0.0.1-application.zip
+config
+myfolder
-oldfile.png
-application.properties
+lib
+springdemo-0.0.1.jar
+start.sh
-springdemo-0.0.1.jar //running this jar file
Usually when you deploy an application (or start it using Java), you start a JAR file. You don't have a resource folder. You can have one and access it, too, but it certainly won't be src/main/resources.
When you build your final artifact (your application), it creates a JAR (or EAR or WAR) file and your resources, which you had in your src/main/resources-folder, are copied over to the output directory and included in the final artifact. That folder simply does not exist when the application is run (assuming you are trying to run it standalone).
During the build process target/ is created and contains the classes, resources, test-resources and the likes (assuming you are building with Maven; it is a little different if you build using Gradle or Ant or by hand).
What you can do is create a folder e.g. docs next to your final artifact, give it the appropriate permissions (chmod/chown) and have your application output files into that folder. This folder is then expected to exist on the target machine running your artifact, too, so if it doesn't, it would mean the folder does not exist or the application lacks the proper permissions to read from / write to that folder.
If you need more details, don't hesitate to ask.
Update:
To access a resource, which is bundled and hence inside your artifact (e.g. final.jar), you should be able to retrieve it by using e.g. the following:
testText = new String(ControllerClass.class.getResourceAsStream("/test.txt").readAllBytes());
This is assuming your test.txt file is right under src/main/resources and was bundled to be directly in the root of your JAR-file (or target folder where your application is run from). ControllerClass is the controller, which is accessing the file. readAllBytes just does exactly this: read all the bytes from a text file. For accessing images inside your artifact, you might want to use ImageIO.
IF you however want to access an external file, which is not bundled and hence not inside your artifact, you may use File image = new File(...) where ... would be something like "docs/image.png". This would require you to create a folder called docs next to your JAR-artifact and put a file image.png inside of it.
You of course also may work with streams and there are various helpful libraries for working with input- and output streams.
The following was meant for AWT, but it works in case you really want to access the bytes of your image: ImageIO. In a controller you usually wouldn't want to do that, but rather have your users access (and thus download) it from a given available folder.
I hope this helps :).
I have a problem with saving files and then downloading them after generating a .war file.
I need to handle the generation of many files after pressing the button by admin in the application. The files are generated using part of the code that was sent using the POST method and second part is from the database.
The files are hundreds / thousands and it is impossible to do it manually. Admin generates files from time to time. The user should be able to download these files from the application.
When I run the application in IntelliJ, app has access to the folders on the disk, so the following code works:
(part of backend class, responfible for saving files in path)
private void saveTextToFile(String text, String fileName) {
String filePathAndName = "/static/myFiles/" + fileName+ ".txt";
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(".").getFile() + filePathAndName );
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(file);
PrintWriter printWriter = new PrintWriter(fileWriter);
printWriter.print(text);
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
The file was saved in folder:
C:\Users...\myProject\target\classes\static.
(and this is link to generated file in thymeleaf)
<html xmlns:th="http://www.thymeleaf.org">
<a th:href="#{|/myFiles/${thisIsMyFileName}|}">Download file</a>
</html>
Unfortunately, when I generate the .war file and run it, the files are not saved in the application's "resources" folder. As a result, the user cannot download this file via the link generated by thymeleaf.
In general, you do not want to upload anything into your application's files - it opens you to many security problems if someone figures out how to overwrite parts of the application, and in most application servers, it is simply not writable.
A much better approach is to have a designated server folder where you can write things. For example, you could have the following in your configuration:
myapp.base-folder = /any/server/folder/you/want
And then, in the code, you would find that folder as follows:
// env is an #AutoWired private Environment
File baseFolder = new File(env.getProperty("myapp.base-folder"));
I find this better than using a database (as #Stultuske suggested in comments), because databases are great for relations, but mostly overkill for actual files. Files can be accessed externally without firing up the database with minimal hassle, and having them separate keeps your database much easier to backup.
To generate links to the file, simply create a link as you would to any other type of request
<a th:href="#{/file/${fileId}|}">Download file</a>
-- and to handle it in the server, but returning the contents of the file:
#GetMapping(value="/file/{id}")
public StreamingResponseBody getFile(#PathVariable long id) throws IOException {
File f = new File(baseFolder, ""+id); // numerical id prevents filesytem traversal
InputStream in;
if (f.exists()) {
in = new BufferedInputStream(new FileInputStream(f));
} else {
// you could also signal error by returning a 404
in = new BufferedInputStream(getClass().getClassLoader()
.getResourceAsStream("static/img/unknown-id.jpg"));
}
return new StreamingResponseBody() {
#Override
public void writeTo(OutputStream os) throws IOException {
FileCopyUtils.copy(in, os);
}
};
}
I prefer numerical IDs to avoid hassles with path traversal - but you can easily use string filenames instead, and deal with security issues by carefully checking that the canonical path of the requested file starts with the canonical path of your baseFolder
Hi all I am having 2 jar files(read.jar, write.jar) in the following folder structure:
app/read/read.jar
app/write/write.jar
The write.jar writes the values to the properties file present in app/important.properties and the read.jar reads from the app/important.properties. In the Java code I am calling the properties file using
FileOutputStream out = new FileOutputStream("/app/important.properties");
This is working fine in Windows OS, but when I put this app in Linux OS in /home/workspace/app a FileNotFoundException is thrown. Then I changed the reading of file to:
FileOutputStream out = new FileOutputStream("./important.properties")
which also produced a FileNotFoundException. Can anyone help me please? Thanks.
FileOutputStream will create the file if it does not exist but it will not create any directory parts and fail with an FileNotFoundException if the directory does not exist. You should check if the directory exist or not before writing.
Also check the write permissions on that directory in unix.
Do it like this:
public static void loadProperFile(String fileName){
try {
String url=ReadProperties.class.getResource("/").toURI().getPath();
String path=url+fileName;
properties.load(new FileInputStream(path));
} catch (Exception e) {
log.error(e.getMessage());
}
}
It works on mac and linux.I hope this will help you!
Need a little bit of help with this one.
My goal is to have an executable jar file that takes a screen-capture of a webpage and works on both windows and linux machines. I have tried using html2image but the results from phantomjs were exponentially better.
I have code that looks like this:
RESOURCE_PATH = MyClass.class.getClassLoader().getResource("resources").getPath();
public static void main (String[] args) {
String url = args[1];
String outFilePath = args[0];
final String phantomjsHome = RESOURCE_PATH + "/phantomjs/";
ProcessBuilder pb = new ProcessBuilder(phantomjsHome + "phantomjs.exe", phantomjsRasterizeScript, url, outFilePath);
Process process = pb.start();
process.waitFor();
}
Now I have tests which assure me when I'm running this as a java application it works fine but when I build an executable jar I get an error. I have checked and double checked that the RESOURCE_FOLDER is pointing at the correct location. But when I run the jar using
java -jar MyProject.jar "google.png" "https://google.com"
I get a
java.io.Exception: Cannot run program "file:/C:/Users/Joe/MyProject.jar/resources/phantomjs.exe": CreateProcess error=2, The system cannot find file specified
By the way this is my first time asking a question on SO, so if you need additional info or have any suggestions or comments on phrasing comment with some feedback. Thank You!
UPDATE
After some more searching I found that an executable could not be executed from within the jar. I have created a method to copy the executable to outside the jar which seems to work.
private static String loadPhantomJS() {
String phantomJs = "phantomjs.exe";
try {
InputStream in = WebShot.class.getResourceAsStream("/resources/phantomjs/" + phantomJs);
File fileOut = new File(storePath + phantomJs);
OutputStream out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
return fileOut.getAbsolutePath();
} catch (Exception e) {
return "";
}
}
please note that this method only works for windows machines, change the file path for linux.
The above method works for Windows machines, note though that any file you want to run must also exist unpacked, outside the jar file. A similar method to loadPhantomJS can be used to unpack other resource files from the jar file. I used this method:
private static void makeLocalFile(String outPath, InputStream is) {
try {
InputStream is;
File fileOut = new File(outPath);
OutputStream out;
out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
} catch (Exception e) {
System.out.println(e);
}
}
I get an InputStream from my resources using, MyClass.class.getResourceAsStream("jsFile.js"). The only way I was able to get it to work so far on linux is by actually installing phantomjs the linux instillation first. Will update this answer if/when I find a better solution.
I have finished developing a java web app using spring and hibernate. In my app, there's a download function. The function runs well on windows env. But when I deploy and run the app on linux env, using Tomcat as the server, the function return zero byte file. The file type is excel (xls). But the browser returns this as pdf file.
Download Function Failed:
Xls File Path on Linux:
and here is the code:
#RequestMapping("downloadXlsTemplate")
public String downloadTemplate(HttpServletRequest request, HttpServletResponse response) {
try {
String filename = "Template.xls";
File onLinux = new File("/opt/tomcat7/webapps/xls/" + filename);
response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition", "attachment; filename=" + filename);
response.setContentLength((int) onLinux.length());
InputStream inputStream = new FileInputStream(onLinux);
OutputStream responseOutputStream = response.getOutputStream();
int bytes;
while((bytes = inputStream.read()) != -1) {
responseOutputStream.write(bytes);
}
inputStream.close();
responseOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
I have tried various ways, but none were successful.
I will really appreciate any idea, help, or solution
Regards
Yunus
The problem you are facing is a file permission problem. The file is owned by 'root' and your tomcat runs on other user.
Try to move the files to a shared location where the tomcat user can access it. Try the /tmp location or any other shared location.
If it is permission issue, try using chmod unix command giving required permission on file .
e.g., chmod u+rwx
As a good practice, try to refer the file using relative path (using class path resource) instead of absolute path (so it is environment independent).