I am trying to save an uploaded file into the file system directory, and allow other users to download it.
I am currently saving it in my database and not in my file system directory. Here is my code:
class Document {
String filename
byte[] filedata
Date uploadDate = new Date()
static constraints = {
filename(blank: false, nullable:false)
filedata(blank: true, nullable: true, maxSize:1073741824)
}
}
and my controller for uploading the file is:
class DocumentController {
static allowedMethods = [delete: "POST"]
def index = {
redirect(action: "list", params: params)
}
def list() {
params.max = 10
[documentInstanceList: Document.list(params), documentInstanceTotal: Document.count()]
}
def uploadPage() {
}
def upload() {
def file = request.getFile('file')
if(file.isEmpty())
{
flash.message = "File cannot be empty"
}
else
{
def documentInstance = new Document()
documentInstance.filename = file.getOriginalFilename()
documentInstance.filedata = file.getBytes()
documentInstance.save()
}
redirect (action: 'list')
}
}
I think you could do a fuction similar to the one below:
boolean upload(MultipartFile uploadFile, String fileUploadDir){
String uploadDir = !fileUploadDir.equals('') ?: 'C:/temp' //You define the path where the file will be saved
File newFile = new File("$uploadDir/${uploadFile.originalFilename}"); //You create the destination file
uploadFile.transferTo(newFile); //Transfer the data
/**You would need to create an independent Domain where to store the path of the file or have the path directly in your domain*/
}
Since you will only need to save the path of the file you could add a string to your domain to store it or you could create an independent domain to store the data of your file. You will also need to add try/catch statements where needed.
And to retrieve the file you would need to add to your controller something like the next code:
File downloadFile = new File(yourFileDomain?.pathProperty) //get the file using the data you saved in your domain
if(downloadFile){ //Set your response properties
response.characterEncoding = "UTF-8"
response.setHeader "Content-disposition", "attachment; filename=\"${yourFileDomain?.fileNameProperty}\"" //add the header with the filename you saved in your domain you could also set a default filename
//response.setHeader "Content-disposition", "attachment; filename=\"myfile.txt\""
response.outputStream << new FileInputStream(downloadFile)
response.outputStream.flush()
return
}
Hope this helps, any comments are welcome.
Related
I have a method in my controller that allows to download the file that was uploaded. I am trying to have the Content-Length header be added to the download method so download progress bars work.
Problem is mine is not working which is response.setContentLength("${documentInstance.fileSize}")
I am getting error that file not found. If it take off this method the download will work
Here is the method
def download(long id) {
Document documentInstance = Document.get(id)
if ( documentInstance == null) {
flash.message = "Document not found."
redirect (action:'list')
} else {
response.setContentType("APPLICATION/OCTET-STREAM")
response.setHeader("Content-Disposition", "Attachment;Filename=\"${documentInstance.filename}\"")
response.setContentLength("${documentInstance.fileSize}")
def file = new File(documentInstance.fullPath)
def fileInputStream = new FileInputStream(file)
def outputStream = response.getOutputStream()
byte[] buffer = new byte[4096];
int len;
while ((len = fileInputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len);
}
outputStream.flush()
outputStream.close()
fileInputStream.close()
}
}
You have to set it has a Header parameter:
response.setHeader("Content-Length", "${bytes.length}")
Also, you might want to disable rendering of the view after you've streamed the file.
webRequest.renderView = false
Can anyone help me how to download an image from url in grails. Currently I am using the following code, but it is saving in current folder of the application. I want to download browser specific folder(like default folder which we download some file from web or saveAS)
def imageDownload() {
//imageURL = "http://www.google.com/images/logo.png"
String fullPath = params.imageURL
String baseName = FilenameUtils.getBaseName(fullPath);
String extension = FilenameUtils.getExtension(fullPath);
def fileName = baseName+"."+extension
def fileDoc = new File(fullPath);
def webUtils = WebUtils.retrieveGrailsWebRequest()
def response = webUtils.getCurrentResponse()
response.setContentType("application/png")
response.setHeader "Content-disposition", "attachment; filename=\"${fileName}\"";
def file = new FileOutputStream(fullPath.tokenize("/")[-1])
def out = new BufferedOutputStream(file)
out << new URL(fullPath).openStream()
out.close()
redirect(action: "imageDetails", params:params)
}
Need help, Thank you.
def downloadImage = {
def fileURL = "http://www.google.com/images/logo.gif"
def thisUrl = new URL(fileURL);
def connection = thisUrl.openConnection();
def dataStream = connection.inputStream
response.setContentType("application/octet-stream")
response.setHeader('Content-disposition', 'Attachment; filename=logo.gif')
response.outputStream << dataStream
response.outputStream.flush()
}
you can do it easily with a few groovy tricks:
URL urlCont = new URL(imageURL);
InputStream inStream = new BufferedInputStream(urlCont.openStream());
byte[] bytes = IOUtils.toByteArray(inStream);
def download() {
String fullPath = params.imageURL
String baseName = FilenameUtils.getBaseName(fullPath);
String extension = FilenameUtils.getExtension(fullPath);
def fileName = baseName+"."+extension
def webUtils = WebUtils.retrieveGrailsWebRequest()
def response = webUtils.getCurrentResponse()
response.setContentType("application/png")
response.setHeader "Content-disposition", "attachment; filename=\"${fileName}\"";
def outputStream = response.getOutputStream()
URL url = new URL(fullPath);
InputStream is = new BufferedInputStream(url.openStream());
byte[] buffer = new byte[1024];
int length=0;
while (-1!=(length=is.read(buffer)))
{
outputStream.write(buffer, 0, length);
}
outputStream.close();
is.close();
}
Thats all I am using..It is downloaded successfully...
I am saving image files in my web folder. But at the time of saving or suppose a user want to change his picture than i want to delete the old picture and save the new one with the same file name. But I am failing after trying. Can anyone please help me on this please? Here is all my action below :
my save action >>>
def savePicture = {
String message = ""
def user = User.findById(1)
def userId = user.id
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
CommonsMultipartFile f = (CommonsMultipartFile) mpr.getFile("productPic");
def okcontents = ['image/png', 'image/jpeg', 'image/gif']
if (! okcontents.contains(f.getContentType())) {
message = "Avatar must be one of: ${okcontents}"
render(view:'uploadForm', model:[message: message])
return;
}
String type = f.getContentType().substring(6)
String baseImageName = java.util.UUID.randomUUID().toString();
baseImageName = "user${user.id}"
// Saving image in a folder assets/channelImage/, in the web-app, with the name: baseImageName
def downloadedFile = f //.getFile( "product.baseImage" )
String fileUploaded = fileUploadService.uploadFile( downloadedFile, "${baseImageName}.${type}", "assets/channelImage/" )
if( fileUploaded ){
user.avatarType = type
user.save()
message = "File Saved Successfully."
redirect(action: 'show', params: [userId: userId])
}
}
my service action where I am trying to delete before save >>>
def String uploadFile( MultipartFile file, String name, String destinationDirectory ) {
def serveletContext = ServletContextHolder.servletContext
def storagePath = serveletContext.getRealPath( destinationDirectory )
def storagePathDirectory = new File("${storagePath}/${name}").delete()
// Store file
if(!file.isEmpty()){
file.transferTo( new File("${storagePath}/${name}") )
println("Saved File: ${storagePath}/${name}")
return "${storagePath}/${name}"
}else{
println "File: ${file.inspect()} was empty"
return null
}
}
my show method in controller >>>
def show = {
Long uid = Long.parseLong(params.userId)
def avatarUser = User.get(uid)
String link = "user${avatarUser.id}.${avatarUser.avatarType}"
[link:link]
}
my view page >>>
<g:if test="${link}">
<img src="${resource(dir: 'assets/channelImage', file: "${link}")}" />
</g:if>
I am encountering a problem in getting the download prompt. In the below code first am allowing the user to upload a file to compress. Once the file is compressed the user should be provided with the compressed files. But in the below code download prompt doesn't appears neither it shows any error. Please help me by correcting my code
The view code:
function CompressFile(box) {
var file = document.getElementById('fileComp');
if (file.value == "") {
alert("Choose a file to upload");
return false;
}
dhtmlx.modalbox.hide(box);
var fd = new FormData();
fd.append('file', file.files[0]);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/FileUpload/Compress', true);
xhr.send(fd);
}
The controller code:
public ActionResult Compress(HttpPostedFileBase file)
{
var supportedType = new[] { "pdf" };
var fileExt = System.IO.Path.GetExtension(file.FileName).Substring(1);
var filename = Path.GetFileNameWithoutExtension(file.FileName) ?? "";
if (file.ContentLength > 0 && supportedType.Contains(fileExt))
{
string filePath = Path.Combine(HttpContext.Server.MapPath(_uploadPDF), Path.GetFileName(file.FileName));
file.SaveAs(filePath);
PdfReader reader = new PdfReader(filePath);
string name = DateTime.Now.ToString("ddMM_HHmmss");
name = Server.MapPath(_fileUploadPath + name + ".pdf");
PdfStamper stamper = new PdfStamper(reader, new FileStream(name, FileMode.Create), PdfWriter.VERSION_1_5);
stamper.FormFlattening = true;
stamper.SetFullCompression();
stamper.Close();
string fn = System.IO.Path.GetFileName(name);
return base.File(name, "application/pdf",fn);
}
else
{
return View();
}
}
The problem is that you're using Ajax. You can't download a file through Ajax. You need to do a regular POST to the ActionMethod. That way the browser can send you back the file and prompt the user where he wants to save it.
I have to create a .xls file from the data displayed in a table in my page. This happens when the user clicks 'export' button. I have the following code for it and it is created okay. Now, I want to open this file in the same click. How should I open it for user to see it?
string filePath = "C:/Upload/Stats_" + viewModel.SelectedTest.ToString() + ".xls";
//write the header
using (var pw = new StreamWriter(filePath, true))
{
pw.WriteLine(String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", "Month", "Total Users", "K",
"T", "G", "Detail", "GS",
"BI", "GHF","A"));
//write to the file
for (int i = 0; i < 12; i++)
{
pw.WriteLine(
String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", viewModel.Months[i],
viewModel.M[i], viewModel.MKau[i],
viewModel.MTech[i], viewModel.MGew[i],
viewModel.MDet[i], viewModel.MGes[i],
viewModel.MBea[i], viewModel.MGesHf[i],viewModel.MAug[i]));
pw.Flush();
}
pw.Close();
}
Here I would like to open it.
I had the same 'requirement' to be able to export to xls, and instead I gave the client an export to csv, which will open in excel if you are on a machine with excel installed but is also available to other systems. I achieved it like this.
Create an extension method that supports .AsCsv, which was taken largely from Mike Hadlow's implementation
public static class EnumerableExtensions
{
public static string AsCsv<T>(this IEnumerable<T> items) where T : class
{
var csvBuilder = new StringBuilder();
var properties = typeof(T).GetProperties();
foreach (T item in items)
{
string line = string.Join(",", properties.Select(p => p.GetValue(item, null).ToCsvValue()).ToArray());
csvBuilder.AppendLine(line);
}
return csvBuilder.ToString();
}
private static string ToCsvValue<T>(this T item)
{
if (item is string)
{
return string.Format("\"{0}\"", item.ToString().Replace("\"", "\\\""));
}
double dummy;
if (double.TryParse(item.ToString(), out dummy))
{
return string.Format("{0}", item.ToString());
}
return string.Format("\"{0}\"", item.ToString());
}
}
Then you would need set your controller method to return a FileContentResult and have some logic like this within the controller method:
var outputModel = viewModel.ToList().Select(model => new
{
Months = model.Months
M = model.M[i],
MKau= model.MKau,
MTech = model.MTech,
MGew = model.MGew,
MDet = model.MDet,
MGes = model.MGes,
MBea= model.MBea,
MGesHf= model.MGesHf
});
string csv = "\"Month\",\"Total Users\",\"K\",\"T\",\"G\",\"Detail\",\"GS\",\"BI\",\"GHF\",\"A\""
+ System.Environment.NewLine
+ outputModel.AsCsv();
string fileName = "Stats_" + viewModel.SelectedTest.ToString() + ".csv"
return this.File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", fileName);