Showing an image on broswer using #ResponseBody in spring boot - java

Hello i have this code to display an immage saved on my filesystem on broswer:
#GetMapping(value = "/prova/img/{id}", produces = MediaType.IMAGE_JPEG_VALUE)
public #ResponseBody byte[] getImageWithMediaType(#PathVariable String id) throws IOException {
String path = uploadFolderPath +"/"+ id;
if(Files.exists(Paths.get(path)) && !Files.isDirectory(Paths.get(path))) {
InputStream in = getClass().getResourceAsStream(path);
return IOUtils.toByteArray(in);
}else {
return null; //this is just for example it should never get here
}
I'm getting this error:
Cannot invoke "java.io.InputStream.read(byte[])" because "input" is null
Any suggestion?

Your code first tests that your input exists (as a File) and is not a directory, then you go ahead and try to read it as a resource from the class path using getClass().getResourceAsStream(path). This is usually not what you want.
Try instead InputStream in = new FileInputStream(path);.
Like this:
if (Files.exists(Paths.get(path)) && !Files.isDirectory(Paths.get(path))) {
InputStream in = new FileInputStream(path);
return IOUtils.toByteArray(in);
}
PS: If you are on Java 9 or later, you don't need the IOUtils dependency, simply use readAllBytes. And as you already use Files and Path, we can clean up the code a bit like this:
Path filePath = Paths.get(path);
if (Files.exists(filePath) && !Files.isDirectory(filePath)) {
InputStream in = Files.newInputStream(filePath, StandardOpenOption.READ);
return in.readAllBytes();
}

Related

SpringBoot absolute path clarification

I'm new to SpringBoot web dev.
I need to save an image to a directory in the current project. I have given path as "String uploaddir = "./src/main/imageuploads/"+ savedadvert.getId();" but the image not save to the "./src/main/imageuploads/" directory in eclipse project.
#RequestMapping(value="/upload", method = RequestMethod.POST)
public String FileUpload(#RequestParam("file1Url") MultipartFile multipartfile, Model model) throws IOException {
model.addAttribute("advertsim",new advertsummary());
advertsummary advert = new advertsummary();
String file1Urlname= StringUtils.cleanPath(multipartfile.getOriginalFilename());
advert.setFile1Url(file1Urlname);
advertsummary savedadvert = AdvertService.addadvert(advert);
String uploaddir = "./src/main/imageuploads/"+ savedadvert.getId();
FileUploadUtil.saveFile(multipartfile, file1Urlname, uploaddir);
return "uploadview";
}
This is the saveFile method for ref.
public static void saveFile(MultipartFile multipartFile, String fileName, String uploadDir) throws IOException {
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
try (InputStream inputStream = multipartFile.getInputStream()) {
Path filePath = uploadPath.resolve(fileName);
System.out.println(filePath.toFile().getAbsolutePath());
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ioe) {
throw new IOException("Could not save image file: " + fileName, ioe);
}
}
I need to upload the image to this directory,
when I get the absolute path, it shows like this "/Users/chathura/eclipse/jee-2021-03/Eclipse.app/Contents/MacOS/./src/main/imageuploads/24/new file.jpg".
There is no way to go to this directory but I can access that directory using the terminal.
Please tell me what is the mistake here?
Note : I'm using macos
Thanks in advance
Could you try 'src/main/resources/imagesuploads' (without .)
Just a reminder: This directory will disappear when you package your application (production mode)
This directory should be configurable from an external file (application. properties for example)
Thank you Ali, your response gave a lead to the solution. My project sits on MacOS partition therefore, I couldn't write a file without permission. I simply changed the location to another partition and it worked.
#RequestMapping(value="/upload", method = RequestMethod.POST)
public String FileUpload(#RequestParam("file1Url") MultipartFile multipartfile, Model model) throws IOException {
model.addAttribute("advertsim",new advertsummary());
advertsummary advert = new advertsummary();
String file1Urlname= StringUtils.cleanPath(multipartfile.getOriginalFilename());
advert.setFile1Url(file1Urlname);
advertsummary savedadvert = AdvertService.addadvert(advert);
String uploaddir = "/Volumes/My Data/Fileupload"+ savedadvert.getId();
FileUploadUtil.saveFile(multipartfile, file1Urlname, uploaddir);
return "uploadview";
}
Thank you

How to sanitize a file with ESAPI?

I am currently trying to resolve the following vulnerability:
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
I have searched many posts and documentation of all kinds and in all situations it is only explained how to solve it in cases where you have a front.
In my case it is only a microservice that communicates with other microservices, and the only validation I do is of the file name. But not the content of the file. Since it is a microservice in charge of uploading an infinity of files of all kinds to a repository.
#PostMapping("uploadFile")
public ResponseEntity<String> uploadDatos(#RequestParam MultipartFile file,
#RequestParam(required = false) String directory)
{
File fileCast= service.multipartfileToFile(file);
if (directory == null)
return new ResponseEntity<String>(service.uploadFile(fileCast, ""), HttpStatus.OK);
else
return new ResponseEntity<String>(service.uploadFile(fileCast, directory), HttpStatus.OK);
}
The method of cast multipart file to file.
public File multipartfileToFile(MultipartFile file) {
String filename = FilenameUtils.normalize(file.getOriginalFilename());
// This utils is mine for extra validation
if (Utils.isValidFilename(filename)) {
throw new IllegalArgumentException();
}
File convFile = new File(filename);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
}
.... // Catch clauses...
return convFile;
}
And honestly I don't know what to do to validate the file, it's probably silly

Using static resources inside a jar library (to be used in Android)

I am developing a plain java library (jar), which contains some static files, which I put to src/main/resources. These static files are used to execute an algorithm and return processed data to the user.
public String getStringFromFile(String fileName) {
String text = "";
try {
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(fileName).getFile());
Scanner scanner = new Scanner(file);
text = scanner.useDelimiter("\\A").next();
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return text;
}
So far so good. However, when I try to use this library/method in an Android project I get:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.net.URL.getFile()' on a null object reference
I want my static resource files to be published with the library. Am I doing something wrong? Any thoughts?
Ok. I think I have solved this. Following this article I created a res directory in the root of my jar module (on the same level as the src directory) and put my files there (helloworld.json). Then added this to build.gradle:
jar {
into('resourcez') {
from 'res'
}
}
Using this helper function (inside the jar lib) and getResourceAsStream() I get the contents of my resource files:
public String getModelFromStream(String fileName) {
final String classpath = "resourcez/";
ClassLoader classLoader = DexiModelLoader.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream(fileName);
if (resourceAsStream == null)
resourceAsStream = classLoader.getResourceAsStream(classpath + fileName);
if (resourceAsStream == null)
return "error";
Scanner s = new Scanner(resourceAsStream).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
After this I simply call getStringFromStream("helloworld.json") or getStringFromStream("resourcez/helloworld.json") in my android app and voilĂ !

How to write a FileTypeDetector for zip archives?

For this package, one of my next steps is to write a series of FileTypeDetector to have the method Files.probeContentType() be smarter than what is is by default (the default provided file type detector relies on "file name extensions" only).
As the javadoc of the aforementioned method mentions, this method relies on instances of FileTypeDetectors be declared in a META-INF/services file.
I have first tested with a simple provider to detect PNG files using the file header:
public final class PngFileTypeDetector
extends FileTypeDetector
{
private static final byte[] PNG_HEADER = {
(byte) 0x89,
(byte) 0x50, (byte) 0x4E, (byte) 0x47,
(byte) 0x0D, (byte) 0x0A,
(byte) 0x1A,
(byte) 0x0A
};
private static final int PNG_HEADER_SIZE = PNG_HEADER.length;
#Override
public String probeContentType(final Path path)
throws IOException
{
final byte[] buf = new byte[PNG_HEADER_SIZE];
try (
final InputStream in = Files.newInputStream(path);
) {
if (in.read(buf) != PNG_HEADER_SIZE)
return null;
}
return Arrays.equals(buf, PNG_HEADER) ? "image/png" : null;
}
}
It works. Now, after a quick glance at the API, I thought this would be a good way to detect whether a file was a zip:
public final class ZipFileTypeDetector
extends FileTypeDetector
{
#Override
public String probeContentType(final Path path)
throws IOException
{
// Rely on what the JDK has to offer...
try (
final InputStream in = Files.newInputStream(path);
final ZipInputStream z = new ZipInputStream(in);
) {
z.getNextEntry();
return "application/zip";
} catch (ZipException ignored) {
return null;
}
}
}
The content of META-INF/services/java.nio.file.spi.FileTypeDetector was this:
com.github.fge.filesystem.ftd.PngFileTypeDetector
com.github.fge.filesystem.ftd.ZipFileTypeDetector
With the current tests, it worked; for the zip I created an empty zip file, for the PNG test I used this image.
Full test:
public final class FileTypeDetectorTest
{
private FileSystem fs;
private Path path;
#BeforeMethod
public void initfs()
throws IOException
{
fs = MemoryFileSystemBuilder.newLinux().build("testfs");
path = fs.getPath("/foo");
}
#DataProvider
public Iterator<Object[]> samples()
{
final List<Object[]> list = new ArrayList<>();
String resourcePath;
String mimeType;
resourcePath = "/ftd/sample.png";
mimeType = "image/png";
list.add(new Object[] { resourcePath, mimeType });
resourcePath = "/ftd/sample.zip";
mimeType = "application/zip";
list.add(new Object[] { resourcePath, mimeType });
return list.iterator();
}
#Test(dataProvider = "samples")
public void fileTypeDetectionTest(final String resourcePath,
final String mimeType)
throws IOException
{
#SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
final InputStream in
= FileTypeDetectorTest.class.getResourceAsStream(resourcePath);
if (in == null)
throw new IOException(resourcePath + " not found in classpath");
try (
final InputStream inref = in;
) {
Files.copy(inref, path);
}
assertThat(Files.probeContentType(path)).isEqualTo(mimeType);
}
#AfterMethod
public void closefs()
throws IOException
{
fs.close();
}
}
However...
If I invert the list of implementations in the services file, that is the file now is:
com.github.fge.filesystem.ftd.ZipFileTypeDetector
com.github.fge.filesystem.ftd.PngFileTypeDetector
then the PNG file is detected as being a zip file!
After some debugging I noticed that:
opening the PNG as a ZipInputStream did not fail...
... and .getNextEntry() returned null!
I'd have expected at least .getNextEntry() to throw ZipException.
Why didn't it? How can I detect reliably whether a file is a zip?
Further note: this is for Paths; therefore anything File is unusable.
Why didn't it?
Well, the JavaDoc for getNextEntry() says that a ZipException or IOException occurs,
if a ZIP file error has occurred
if an I/O error has occurred
respectively.
Based on that wonderfully helpful information (cough), we can't make any assumptions that it will throw an exception if it encounters an invalid entry.
How can I detect reliably whether a file is a zip?
The ZIP file format specification, which was originally PKZip, can be found here. While its all a good read :), take a look at section 4; 4.3.16 in particular. It specifies the "End of central directory record", which all ZIP files have (even empty ones).

Can't load a BufferedImage

I have a form with that code:
public Form()
{
initComponents();
try
{
File file= new File("avatar.jpg");
BufferedImage image= ImageIO.read(file);
}
catch (IOException ex)
{
System.out.println("Failed to load image");
}
}
The problem is that the code always throws the IOException and enters in the catch block.
So the file isn't read.
I have created the project with Netbeans 7.2, and the directory looks like this:
What's the problem? Maybe the file shouldn't be there but in the father directory? Or what?
Is your image being packaged within your jar? to find this out, extract you jar file like you would an ordinary zip file and check if the image is anywhere there (normally located by jarname\packagename\filename. If so then you'll need to extract your image as a resource using getResourceAsStream().
It would be something like:
public class Test {
private static final String absName = "/yourpackage/yourimage.jpg";
public static void main(String[] args) {
Class c=null;
try {
c = Class.forName("yourpackage.Test");//pkg is the package name in which the resource lies
} catch (Exception ex) {
// This should not happen.
}
InputStream s = c.getResourceAsStream(absName);
// do something with it.
}
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader();
if (cl==null) {
return ClassLoader.getSystemResourceAsStream(name); // A system class.
}
return cl.getResourceAsStream(name);
}
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader();
if (cl==null) {
return ClassLoader.getSystemResource(name); // A system class.
}
return cl.getResource(name);
}
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/') + "/" + name;
}
} else {
name = name.substring(1);
}
return name;
}
}
Reference:
Accessing Resources
It looks like you have a namespace of poker.*
It all depends on where the jvm is initialized from.
Where is your main? Is it in /Users/ramy/NetBeansProjects/Poker/src?
Also, I suggest you use getResource() for all of your file loading needs, especially inside jars.
this.getClass().getResource("/resource/buttons1.png")
or
this.getClass().getResourceAsStream("/resource/TX_Jello2.ttf")
You can find out where your programs default path is by doing the following:
System.getProperty("user.dir");
Without seeing the error I would say the most likely cause is it can't find the file. So I suggest you replace "avatar.jpg" in the File constructor with the absolute file path to it. e.g.
File file = new File("INSERT_PATH_TO_FILE/avatar.jpg");
You cannot assume the image will be "there" because the relative path between your .java and the image seems ok.
Accessing a resource depends of your "kind" of project (Web, standalone....). In your case, you can try to get the image from your classpath
final File inputFile = new ClassPathResource("....").getFile();
final BufferedImage inputImg = ImageIO.read(inputFile);

Categories

Resources