Grails. Upload files to temp folder and display them in gsp - java

My intention is to upload images and store them in a temp folder. Then I want to display these images in the .gsp views. The process I've been trying to make it to work is something like this:
First, upload the file from input:
<input id="inputImg" type="file" accept="image/*">
Create the file:
def saveFile(MultipartFile inputImg) {
def contentType = inputImg.getContentType()
def originalFilename = inputImg.getOriginalFilename()
def extension = FilenameUtils.getExtension(originalFilename)
String tempPath = System.getProperty("java.io.tmpdir") + "/uploads"
File file = new File("$tempPath/$originalFilename")
FileUtils.forceMkdirParent(file)
inputImg.transferTo(file)
if (contentType == 'application/octet-stream') {
contentType = MimeTypeUtils.getContentTypeByFileName(originalFilename)
}
Path filePath = Paths.get(file.toString())
Path path = Paths.get(tempPath)
Path relativePath = path.relativize(filePath)
Avatar avatar = new Avatar(
path: relativePath.toString(),
contentType: contentType,
name: originalFilename,
extension: extension
)
}
Once is stored in the temp folder, I found this solution but I'm not sure if it's the best way to do it. I'm trying to process the image with base64 encoding before sending it to the view:
def filename = user?.avatar?.name
def file = new File("$tempPath/$filename")
def base64file = file?.readBytes()?.encodeBase64()
And finally show it in the gsp:
<img alt="img" src="data:image/*;base64,${base64file}"/>
I would like to know if there is another best way to do this process, I don't know if I'm missing something or if this isn't a good procedure to manage with files and images...

You are using the inline images with Base64 encoding which is good for displaying relatively small images (up to 5k). The advantage of this approach is that you dump the page WITH images in a single HTTP-connection.
If the images grow considerably larger (> 1MB), then you can not use caching and other nice features, so you have to send the data over the line over and over again and that would slow down user experience.
Another way would be to deliver each image in a separate request.
You could define a controller action like:
class ImageController {
def image(String id){
def file = new File("$tempPath/$id")
if( !file.exists() )
render status: 404
else{
response.contentType = 'image/jpeg'
response.withOutputStream{ it << file.readBytes() }
}
}
}
then in your GSP you put:
<img alt="img" src="${g.createLink( controller:'image', action:'image', id:user.avatar.name )}"/>

Related

How to return an Image to browser in rest API in JAVA from folder?

I have a folder in my NetBeans project with images. I have a H2 database with a "properties" table.
The images are named after a column in the properties table for convenience. This is my code so far.
#PostMapping(value = "/image/large/{id}", produces = MediaType.IMAGE_PNG_VALUE)
public ResponseEntity<Image> getPicture(#PathVariable long id)throws Exception{
System.out.println(id);
//System.out.println(barcode);
Properties prop1 = new Properties();
prop1 = propService.findOne(id);
String filepath = prop1.getPhoto();
String img = "static/images/"+filepath;
return img;
}
How can I implement this in my rest controller? Struggling to find a correct way to implement this, any help appreciated.
From the code you have provided, you can return a string representing an image location or path. This path can then be used in am image <img /> tag.
The second option is to read your file using an inputstream and convert the image to base46 (which you then return to the client).

How to Write/ Edit a txt file using Kotlin in Android Studio?

I am in the beginning of Android App learning phase. I have a .txt file in my assets folder consisting of strings in each line, like this-
AWOL JJ AWOL
Aaronic JJ Aaronic
Aaronical JJ Aaronical
What I want to do is just replace JJ with NN and keep rest the same. My questions are-
Is there a way to edit the already existing file, because all the solutions I found are talking about creating some other file using function File(<filename>)?
If I follow the solutions described on different websites, I can not access the file USING File(), it shows the error that the file can not be found even though I have created an empty file with the same name. I can not access the file if it is inside assets folder or inside app/src. So, instead I am using Context.assets.open(<filename>) for readin the orginal file which opens the file as inputstream. Although I don't know any other way of opening the file using File() for writing.
// FOR READING FROM ORIGINAL FILE
var inputStreamLemmDict = BufferedReader(InputStreamReader(context!!.assets.open("my_file.dict"))).readLines()
// FOR WRITING TO ANOTHER FILE
File("path_to/my_file.txt").bufferedWriter().use { out ->
inputStreamLemmDict.forEach {
var eachLineSplit = it.split("\\s".toRegex())
if (eachLineSplit[1] == "NNN") {
out.write("${eachLineSplit[0]}\tNN\t${eachLineSplit[2]}\n")
}
else {
out.write("${it}\n")
}
}
Any help is appreciated. Thank you!
Hi you can use the following solution to achieve your desired result.
UPDATE : Please try this solution to read file from assets and get your result. This solution is not tested.
Make sure yourfilename.txt is under assets folder.
try {
val inputStream:InputStream = assets.open("yourfilename.txt")
val text = inputStream.bufferedReader().use{it.readText()}
println(text)
text = text.replace("JJ".toRegex(), "NN")
f.writeText(text)
}catch (e:Exception){
Log.d(TAG, e.toString())
}
fun main(args: Array<String>) {
var lineNumber = 0
var newString = ""
File("src/dataFile").forEachLine {
++lineNumber
println("$lineNumber: $it")
newString = it.replace("JJ", "NN")
println("New string : $newString")
}
File("src/dataFile").writeText(newString)
}

How do I email an HTML report (as an attachment) with images embedded?

I am creating a report with ExtentReports to be emailed out to team members outside of the domain. I use a screenshot method (below) to save screenshots of test failures. They are stored in a child folder to the ExtentReports HTML report.
I attach the report to an email, and in it, the images display fine for team members on the domain with folder permission. But I am at a loss for how to allow people outside of that folder's permissions, to see the images embedded in the report. This is the HTML for the image, directly referencing that file.
<img class="report-img" data-featherlight="file:///\\domain.local\files\QA\Projects\AutomationReports\ExtentScreens\1486487870116.jpg" src="file:///\\domain.local\files\QA\Projects\AutomationReports\ExtentScreens\1486487870116.jpg">
Here is my screenshot method.
public static String CaptureScreen(WebDriver driver) {
String ImagesPath = "\\\\domain.local\\files\\QA\\Projects\\AutomationReports\\ExtentScreens\\"
+ new Date().getTime();
TakesScreenshot oScn = (TakesScreenshot) driver;
File oScnShot = oScn.getScreenshotAs(OutputType.FILE);
File oDest = new File(ImagesPath + ".jpg");
// System.out.println(ImagesPath);
try {
FileUtils.copyFile(oScnShot, oDest);
} catch (IOException e) {
System.out.println(e.getMessage());
}
return ImagesPath + ".jpg";
}
I have 2 unrelated ideas on how to fix this. But I need some help getting started with either of them. I'm open to other suggestions.
Embed images directly into the HTML report or somehow send a folder containing screenshots with the HTML report. However, the HTML will still reference my original location and the images will be broken.
Share the folder containing images with Everyone, Guest, and Anonymous User, so people outside of the domain can open HTML that references this location. I don't know how to set these permissions, and I'm not even sure that doing so will allow an external user to view HTML referencing the location.
Please try with base64 encoding it will definitely work.
Also, please check your browser support.
Try this:
<img src="data:image/jpeg;base64,/9j/4AAQxxxxxxxx...." />
Depending on what browsers you need to support, you could embed your images in base64. like this :
<img src="data:image/jpeg;base64, LzlqLzRBQ...<!-- base64 data -->" />
Here is a tool to encode your images
You can embed base64 encoded images directly into HTML document.
<img src="data:image/jpeg;base64,/9j/4AAQxxxxxxxx...." />
You can create a multipart/report message with the images included as additional body parts in the message. The JavaMail FAQ includes this sample code:
Multipart multipart = new MimeMultipart("related");
MimeBodyPart htmlPart = new MimeBodyPart();
// messageBody contains html that references image
// using something like <img src="cid:XXX"> where
// "XXX" is an identifier that you make up to refer
// to the image
htmlPart.setText(messageBody, "utf-8", "html");
multipart.addBodyPart(htmlPart);
MimeBodyPart imgPart = new MimeBodyPart();
// imageFile is the file containing the image
imgPart.attachFile(imageFile);
// or, if the image is in a byte array in memory, use
// imgPart.setDataHandler(new DataHandler(
// new ByteArrayDataSource(bytes, "image/whatever")));
// "XXX" below matches "XXX" above in html code
imgPart.setContentID("<XXX>");
multipart.addBodyPart(imgPart);
message.setContent(multipart);
We should have a class file as below
public class GetScreenShort {
public static String capture(WebDriver driver,String screenShotName)
throws IOException
{
TakesScreenshot ts = (TakesScreenshot)driver;
String dest = ts.getScreenshotAs(OutputType.BASE64);
return "data:image/jpg;base64, " + dest ;
}
}
The same class has to be called as below
String screenShotPath = GetScreenShort.capture(webdriver,
"screenShotName");

How to download 10GB file with Angularjs, Java, Tomcat,Spring and REST?

When I download small file , everything is OK , but I need some way to download large files . If file large, Blob didn't created , haven't enough memory.
Download file without save on client , directly save to disk with many requests on the server or something like that.
My code on server is :
#RequestMapping(value = "/oneFile/{name}", method = RequestMethod.GET)
public void getOneFile( #PathVariable("name") String name, HttpServletResponse response,HttpServletRequest request) {
....
InputStream in = new FileInputStream(new File(file.getAbsolutePath()));
org.apache.commons.io.IOUtils.copy(in, response.getOutputStream());
response.flushBuffer();
On client and this is work for small size:
backupFileServer.downloadOneFileBrow(data)
.success(function(databack) {
var file = new Blob([ databack ], {
type : 'application/csv'
});
var fileURL = URL.createObjectURL(file);
var a = document.createElement('a');
a.href = fileURL;
a.target = '_blank';
a.download = data;
document.body.appendChild(a);
a.click();
})
.error(function() {
alert($scope.DOWNLOAD_ERROR);
});
I tried something like this but didn't work :
var a = document.createElement('a');
a.href = 'data:attachment/csv;charset=utf-8,' + encodeURI(databack);
a.target = '_blank';
a.download = data;
document.body.appendChild(a);
a.click();
How someone idea how to do this or some example or code ....
Thank you in advance
You need to split your file into multiple files and rebuild the file with your server.
Because it's bad practice to upload a big file without splitting it, the user can be disconnect at 99% of the upload and he need to upload the whole file again.
An example here : https://flowjs.github.io/ng-flow/
A good example here : http://ryansouthgate.com/2015/12/24/upload-amazon-s3-using-angularjs/ with Amazon S3 and their SDK.

How to save a CommonsMultipartFile as JPG always (and check if it is an image) in Grails

It works:
View (GSP):
<g:uploadForm action="upload">
<input type="file" name="myImageFile" />
<input type="submit" />
</g:uploadForm>
Controller:
def destination = "D:\\someFolder\\image.jpg";
def f = request.getFile('myImageFile')
f.transferTo(new File(destination))
response.sendError(200, 'Done')
But I want to convert it to a JPG image always. So I tried:
def destination = "D:\\someFolder\\image.jpg";
PlanarImage inputfile = JAI.create("FileLoad", f);
JAI.create("filestore",inputfile,destination,"JPEG");
This is the error:
FileLoad - Parameter values class (org.springframework.web.multipart.commons.CommonsMultipartFile) is not an instance of the parameter class (java.lang.String) for parameter "filename".. Stacktrace follows:
So far, the only solution I have though is to save the image as normally after checking if it is an image (thanks #james-kleeh). Then loading it with JAI.create and do the stuff. Finally deleting the original image.
I also wonder how could I check if the uploaded file is an image.
The GSP code is the same I posted in the question.
The controller code would be like this:
import javax.media.jai.*;
...
def f = request.getFile('myFile')
def okContentTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif']
if (!okContentTypes.contains(f.getContentType())) {
// TODO Tell user: "Image type must be one of: ${okContentTypes}"
}
else {
def destination = "D:\\someFolder\\image.jpg";
byte[] source = f.bytes;
SeekableStream inputStream = new ByteArraySeekableStream(source);
RenderedOp image = JAI.create("stream", inputStream)
JAI.create("filestore",image,destination,"JPEG"); // Destination directory must exist (D:\someFolder\)
}
I hope it is useful for somebody!
Following controller side code I use to save uploaded image outside the application.
def f = request.getFile('myFile')
def okContentTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif']
if (!okContentTypes.contains(f.getContentType())) {
//TODO Tell user: "Image type must be one of: ${okContentTypes}"
} else {
def destination = "/opt/jft/profileImages" //path to dir where images will be saved. In my case profileImages is the destination dir.
File dir = new File(destination)
dir.mkdirs()
f.transferTo(new File(dir, f.getOriginalFilename()))
}
Here you don't need to have existing destination directory, if it does not exists then program will create it.

Categories