Liferay Upload : UploadPortletRequest empty - upload

I am having an issue getting multiple file from an upload using the UploadPortletRequest.
I can see in my ActionRequest that the files are here: using debug i see that actionRequest.multipartFiles.[0].fileItem.tempFile give me the location of the first uploaded file.
Though, in order to get the multipartParameterMap I need to convert the ActionRequest in UploadPortletRequest. when I do :
UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(actionRequest);
My uploadRequest.getSize("fileName")) returns 0...
Do you know what could be the cause?
Do you have another solution to get the temp uploaded files from the ActionRequest ?
Here is the .jsp I use :
<portlet:actionURL var="fileUploadURL">
<portlet:param name="formAction" value="fileUpload" />
</portlet:actionURL>
<form:form name="fileUploader" commandName="springFileVO"
method="post" action="${fileUploadURL}" enctype="multipart/form-data">
<label> Select a File</label>
<input type="file" name="uploadedFile" multiple="multiple">
<input type="submit" value="<liferay-ui:message key="upload" />" onClick="<%= uploadProgressId %>.startProgress(); return true;"/>
</form:form>
<liferay-ui:upload-progress id="<%= uploadProgressId %>" message="uploading" redirect="<%= HtmlUtil.escape(fileUploadURL) %>" />
Here is the Controller :
#ActionMapping(params="formAction=fileUpload")
public void fileUpload(ActionRequest request, ActionResponse response){
UploadPortletRequest uploadPortletRequest = PortalUtil.getUploadPortletRequest(request);
System.out.println("Size: "+uploadPortletRequest.getSize("uploadedFile"));
[...] }
Thank you for your help!

I think you're missing portlet:namespace attribute.
<input type="file" name="<portlet:namespace/>uploadedFile" multiple="multiple">
As your uploading multiple files, you can use following.
UploadPortletRequest uploadPortletRequest = PortalUtil.getUploadPortletRequest(request);
File[] files = uploadPortletRequest.getFiles("uploadedFile");
for (File file : files) {
System.out.println("Size: "+ file.length());
}

Related

Buffer too many uploads?

I am trying to upload a large video file. I am using Azure Storage blob. Reading documentation there is warning about using IFormFile at https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1
It suggests that I stream my data.
Is the follow code creating a buffer there will crash my server , or streaming directly to the storage?
From the View
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<input asp-for="VideoAsFile" class="form-control" />
<span asp-validation-for="VideoAsFile" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
From the controller
public async Task<IActionResult> Create([Bind(" Name,Description,VideoAsFile")] VideoWithFileViewModel video)
{
if (ModelState.IsValid)
{
string imageId;
using (var stream = video.VideoAsFile.OpenReadStream())
{
imageId = videoServices.SaveVideo(stream);
}
var newVideo = new Video()
{
Name = video.Name,
Description = video.Description,
URL = imageId
};
repository.AddVideo(newVideo, User);
repository.SaveAll();
return RedirectToAction(nameof(Index));
}
From the VideoServices
public string SaveVideo(Stream videoStream)
{
CloudBlobClient blobClient=new CloudBlobClient(new Uri(baseUri), credentials);
var imageId = Guid.NewGuid().ToString();
var container = blobClient.GetContainerReference("videos");
var blob = container.GetBlockBlobReference(imageId);
blob.UploadFromStreamAsync(videoStream);
return imageId;
}
IFormFile causes issues because the model binder can only do its thing once the request body has been entirely spooled into memory, which if you have a large upload, could mean using up many gigabytes of RAM or potentially maxing out your RAM utilization entirely.
To buffer the upload, you have to work with the request stream directly, which means turning off model binding entirely on the action. That means you cannot get anything from the action params.
The request body stream will be encoded as multipart/form-data, so you will have to manually parse this into its constituent parts, and bind the data to your entity/model directly, and then read the file part in a buffered way, passing the blocks you read on to your Azure blob storage piece by piece. Microsoft has an example of doing a buffered upload. However, it writes the upload file to disk. Getting it into Azure blob storage is on you.

How can I export data in pdf using MVC?

This is My Index method by which I am getting the list of data in webgird.How can I write a method for exporting this list of data when I click on button?
public ActionResult Index(string eMailId)
{
var refEntry = _moneyReport.GetAll().Where(a => a.EmailId == eMailId).ToList();
var credittotal = _moneyReport.GetAll().Where(a => a.EmailId == eMailId && a.PromoValue < 0).Sum(a => a.PromoValue);
decimal TotalCredit = Convert.ToDecimal(credittotal * -1);
var debittotal = _moneyReport.GetAll().Where(a => a.EmailId == eMailId && a.PromoValue >0).Sum(a => a.PromoValue);
decimal TotalDebit = Convert.ToDecimal(debittotal);
ViewBag.TotDebit = TotalDebit;
ViewBag.TotCredit = TotalCredit;
if(TotalCredit>TotalDebit)
{
decimal FinalTotal = TotalCredit - TotalDebit;
ViewBag.Total = FinalTotal;
}
else
{
decimal FinalTotal = TotalDebit - TotalCredit;
ViewBag.Total = FinalTotal;
}
return View(refEntry);
}
This is my View page where I am entering an emailid,load and Export button`enter code here.
#using (Html.BeginForm())
{
<div class="container-fluid form-row">
<div class="col-md-12 no-padding">
<div class="col-md-3 no-padding">
<input type="text" name="eMailId" id="eMailId" />
<span class="highlight"></span>
<span class="bar"></span>
<label class="no-left">Enter Email Id <sup class="star">*</sup></label>
</div>
<div class="col-md-3">
<input type="text" id="gName" name="gName" readonly="readonly" />
<span class="highlight"></span>
<span class="bar"></span>
<label>Name</label>
</div>
<div class="col-md-3">
<input type="submit" id="btnLoad" class="btn btn-md pm-create" value="Load" />
<input type="submit" id="btnLoad" class="btn btn-md" value="Export To PDF" />
</div>
<input type="hidden" id="HdnEmail" value='#TempData["MailID"]' />
</div>
</div>
}
<div id="report-grid">
#{Html.RenderPartial("ImportMoneyReport", Model);}
</div>
ImPortMoneyReport is my partial page where i ve the webgrid.
To export model data to PDF you will have to use one of third party pdf export libraries such as few below. You will find sample examples on respective sites or google them. You will need to implement code to export pdf in and add that file/stream into Response.OutputStream by setting respective content type in ImportMoneyReport action. Also you will have to invoke ImportMoneyReport method on post/event you can not use Html.RenderPartial to export; otherwise you can put export code in Index action only.
PDF Sharp
iTextSharp
It you want something that's working and very easy to use. Take a look at https://github.com/andyhutch77/MvcRazorToPdf
Just read the documentation.
For sample code. Take a look at this.
https://github.com/andyhutch77/MvcRazorToPdf/tree/master/MvcRazorToPdfExample
If you encounter some issues go to their github page and click the Issues tab, maybe some of your questions are already resolved there.
P.S.
Some of the PDF libraries like Rotativa will require an executable program to run that will not work when your app is deployed to Azure because Azure doesn't support exe files (I guess for security purposes) else you'll create a webjob just for the exe file.

How to prompt Save As dialog on file download

I'm trying to prompt a save as dialog when downloading a file, but what I get is, or the file is opening on a browser or it is downloaded without prompting for the save location and save name.
My Controller's code:
public FileContentResult Save(string text)
{
string contentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment; filename=outname.txt"); //EDIT
return File(Encoding.ASCII.GetBytes(text), contentType, "outname.txt");
}
I've tried a different variations of FileResult/ActionResult, application/text etc.
Client code:
<html>
<body>
<script>
function submitForm() {
txt = document.getElementById("textFld");
form = document.getElementById("submitForm");
input = document.getElementById("messages").outerHTML;
txt.value = input;
form.submit();
};
</script>
<table id="messages"> ... </table>
<form action="Home/Save" method="POST" id="submitForm">
<input type="text" name="text" id="textFld">
</form>
<input type="button" id="submitBtn" onclick="submitForm()">
<script>
subm = document.getElementById("submitBtn");
subm.click();
</script>
</body>
</html>
Original answer
You need to set the Content-Disposition header to attachment in the response to instruct the browser to save the file.
New answer
It looks like this is a known Chrome issue: https://code.google.com/p/chromium/issues/detail?id=380652

How to save uploaded image

I'm wondering how I could save an uploaded image in grails.
The situation:
I have a gsp page with a form, containing a file upload. I tried to get the data from the fileupload, but it just won't work.
In the controller:
def file = request.getFile('fileupload')
appearanceInstance.logo = file.encodeAsBase64().toString()
In the view:
<g:form action="save" enctype="multipart/form-data">
<div class="file-upload">
<label >Choose logo</label>
<input id="fileupload" type="file" name="fileupload" onchange="handleFileSelect(this)"/>
</div><br/>
<br/>
</g:form>
Anyone who had experience with this?
this might be another way to do it, but since I adapt an in the view when an image is selected using the file upoad, can I get the image data from the in the controller?
Thanks in advance!
UPDATE:
to be clear, there are some other controls in the form, from which I get the other parameters to save.
I guess this example Simple Avatar Uploader will answer all your questions
try this i hope this will help you it works for me also see this post
Class SomeController{
def uploader(){
}
def save(){
String s=""
CommonsMultipartFile f=request.getFile('fileupload')
final String name =f.getOriginalFilename()
def fos= new FileOutputStream(new File(name))
f.getBytes().each{ fos.write(it) }
s=Base64.encode(f.getBytes())
fos.flush()
fos.close()
render 'done now refresh your source directory to see the file ${s}'
}
and the view 'uploader.gsp'
<g:form action="save" enctype="multipart/form-data">
<div class="file-upload">
<label>Choose logo</label> <input id="fileupload" type="file"
name="fileupload" />
</div>
<input type="submit" class="buttons" value="Upload" />
</g:form>
Hi try with this one .
def save = {
def requestInstance = new Request(params)
def requestNumberInstance = new RequestNumber()
if(requestInstance.validate() && requestInstance.save(flush: true)){
println "Saved successfully with ${requestInstance.picture1.length} bytes"
}
else {
println "Save failed"
}

uploading a file in grails

I am trying to upload a file in grails in my gsp I have:
<g:form id="update" url="[action: 'updateStatus',]">
<g:textArea name="message" value="" cols="3" rows="1"/><br/>
<g:textField id="tagField" name="tag" value=""/><br/>
<input id="inputField" type="file" name="myFile" enctype="multipart/form-data" />
<g:submitButton name="Update Status"/>
</g:form>
In my controller i have:
def updateStatus(String message) {
if (params.myFile){
def f = request.getFile('myFile')
}
The request get file is failing with this error:
No signature of method: org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper.getFile() is applicable for argument types: (java.lang.String) values: [myFile]
Any ideas why this is as I have and are using getFile in my other controllers which works fine.
here is working file submit:
the form (gsp)
<form method="post" enctype="multipart/form-data">
<p><input type='file' name="cfile"/></p>
<input type='submit'>
</form>
the controller that will store submitted file into 'D:/submitted_file':
def index() {
if(params.cfile){
if(params.cfile instanceof org.springframework.web.multipart.commons.CommonsMultipartFile){
new FileOutputStream('d:/submitted_file').leftShift( params.cfile.getInputStream() );
//params.cfile.transferTo(new File('D:/submitted_file'));
}else{
log.error("wrong attachment type [${cfile.getClass()}]");
}
}
}
this works for me (grails 2.0.4)
You need enctype="multipart/form-data" on the g:form tag to make the browser use a multipart request.
In order to upload a file you must set the enctype on the form. To do so you can make use of the <g:uploadForm> which is identical to the standard form tag except that it sets the enctype attribute to "multipart/form-data" automatically.
I prefer to make use of the Grails Selfie Plugin an Image / File Upload Plugin to attach files to your domain models, upload to a CDN, validate content, or produce thumbnails.
Domain
import com.bertramlabs.plugins.selfie.Attachment
class Book {
String name
Attachment photo
static attachmentOptions = [
photo: [
styles: [
thumb: [width: 50, height: 50, mode: 'fit'],
medium: [width: 250, height: 250, mode: 'scale']
]
]
]
static embedded = ['photo'] //required
static constraints = {
photo contentType: ['image/jpeg','image/png'], fileSize:1024*1024 // 1mb
}
}
GSP
<g:uploadForm name="myUpload" controller="upload" action="updateStatus">
<input type="file" name="myFile" />
</g:uploadForm>
Controller
class PhotoController {
def upload() {
def photo = new Photo(params)
if(!photo.save()) {
println "Error Saving! ${photo.errors.allErrors}"
}
redirect view: "index"
}
}
Sources
1. uploadFrom
2. selfie plugin

Resources