ArrayIndexOutOfBoundsException grails - database

I have this simple controller which uploads a file into the database. I have a working view which displays the form for uploading, but when I click on the upload button, I run into this error at the documentInstance.save() line: ArrayIndexOutOfBoundsException occurred when processing request:[POST]/myApp/documentFile/upload
class DocumentController {
def upload() {
def file = request.getFile('file')
if(file.empty) {
flash.message = "File cannot be empty"
} else {
def documentInstance = new Document()
documentInstance.filename = file.originalFilename
documentInstance.filedata = file.getBytes()
documentInstance.save()
}
redirect (action:'list')
}
}
Can anyone help me understand where the problem lies? Is the information I have given sufficient for answering this? If not please let me know.
UPDATE:
form element part of the gsp is as below.
<g:uploadForm action="upload">
<fieldset class="form">
<input type="file" name="file" />
</fieldset>
<fieldset class="buttons">
<g:submitButton name="upload" class="save" value="Upload" />
</fieldset>
</g:uploadForm>
Here is the Document domain class
class Document{
String filename
byte[] fileData
static constraints = {
filename(blank:false,nullable:false)
filedata(blank: true, nullable:true, maxSize:1073741824)
}
}

Try setting 'size' or 'maxSize' constraints on your domain objects 'filedata' field according to the size of the files you are uploading. Your database might be creating small columns that cannot hold the file size you are uploading. According to http://grails.org/doc/latest/guide/theWebLayer.html#uploadingFiles

Related

How to reduce image size in multi-part FormData file upload

html
<form #form enctype="multipart/form-data">
<input type="file" #upload name='uploadingFiles' (change)="uploadFiles(form)" multiple>
</form>
Angular
void uploadFiles(form) {
var formData = new FormData(form);
final request = new HttpRequest();
request.open('POST', 'http://localhost:8080/uploadMulti');
request.upload.onProgress.listen((ProgressEvent e) {
print('progress');
});
request.onLoad.listen((e) {
print('Uploaded');
});
request.send(formData);
}
How can I put image manipulation code here to reduce an image that is 4000X4000 to 600X600 and then replace it in the formData before sending ? Is it possible or is the formData just meta-data passed to the server and then server uses that to pull image bytes one file at a time ?
Angular has a good package to make a compression on the image before you upload it to your server.
you can use this https://www.npmjs.com/package/ngx-image-compress
and here is a good article if you have doubts about who you can do it.
https://medium.com/swlh/compress-image-and-send-it-to-an-api-in-angular-bc48e6ed3835

Open MultipartFile(Blob storage) in a _blank tab

I have a SpringBoot 2.1.3 + Thymeleaf 3 webapp. I have a big form with some information and also file upload. The uploading file works well, but when I want to reload into the same form (for detail or modify purpose) the information stored into DB everything works well less the part related to the files.
The code, for the uploading file part, is the follow:
<div class="form-group row">
<label for="allegato_durc" class="col-sm-5 col-form-label form-label">Allegato DURC</label>
<div class="col-sm-7">
<input type="file" th:field="*{documentiFornitoreDto.allegato_DURC}" class="form-control-file form-control-sm datif_input" id="allegato_durc">
</div>
<label for="allegato_CCIAA" class="col-sm-5 col-form-label form-label">Allegato CCIAA</label>
<div class="col-sm-7">
<input type="file" th:field="*{documentiFornitoreDto.allegato_CCIAA}" class="form-control-file form-control-sm datif_input" id="allegato_CCIAA">
</div>
</div>
Even if the file is present, I see the input field empty as below:
I'm storing the MultipartFile as MediumBlob into DB and, when I reload the info from DB, I rebuild the MultipartFile as follows:
public class ByteToMultipartFile implements MultipartFile {
private byte[] fileContent;
private String fileName;
public ByteToMultipartFile(String fileName, byte[] fileContent) {
this.fileContent = fileContent;
this.fileName = fileName;
}
#Override
public String getName() {
return fileName;
}
#Override
public String getOriginalFilename() {
return fileName;
}
#Override
public String getContentType() {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean isEmpty() {
if (fileContent.length > 0) return false;
else return true;
}
#Override
public long getSize() {
return fileContent.length;
}
#Override
public byte[] getBytes() throws IOException {
return fileContent;
}
#Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(fileContent);
}
#Override
public void transferTo(File dest) throws IOException, IllegalStateException {
// TODO Auto-generated method stub
}
}
Maybe there's something wrong with the class above??
Anyway I would like to perform 2 things:
1) Show the filename near Choose button (Scegli file in the image) when present
2) Show a button that permit the user to OPEN the file in a properly Windows app (if it is a .pdf open it with acrobat reader and so on)
It is possible to do some??
I have read right here, into a old post, that a file could be open in a new _blank tab (or page makes no difference) this way:
<h4>#document.Name</h4>
that is roughly what I want. Now the author writes that this attr:
#document.ContentBlobURL
represents the blob storage address of the DB. Is there someone who knows what it is?? How can I retrieve that value?
I googling a lot but I couldn't find anything interesting.
I would like to point out that, as you know, in a SpringBoot application (for example) with this structure:
if I save the file on disk, inside static folder for example, I can open it by:
http://localhost:8080/costruzione_stampi.pdf
I would like the same thing but whitout saving files on the disk..
Hope someone will answer..
I found a solution, I wanna post it because I hope it helps somebody else.
Googling around I find out that I can't set value of
<input type="file" ...
in a form with data (I have tried with Multipart, File, Blob, byte[] ecc...) loaded from DB for security reasons.
With this I mean that I can't set the input file value with a procedure like below:
#Controller
public class AppController {
#GetMapping('/loadDataInForm')
public String showData(Model model) {
model.addAttribute('file', repository.getByPk(1)); // suppose that this repository retrive a Blob or MultipartFile or someone else
return "form.html"
}
}
form.html
.....
<input type="file" th:field="*{file}" id="file_data"> // always contains nothing
I found some workaround (one of this is here) but is really not a best practice.
Anyway, if you have a different needs, for example show a preview of the file chosen from user (but at uploading time!!) you can use this trick:
<input type="file" th:field="*{someDto.file}" id="allegato_durc" onchange="show();">
.....
<script type="text/javascript">
function show() {
const fileElem = document.getElementById('allegato_durc').files[0];
var binaryData = [];
binaryData.push(fileElem);
var blob = new Blob(binaryData, {type: "image/jpg"});
const objectURL = window.URL.createObjectURL(blob);
window.open(objectURL, '_blank');
}
</script>
Hope helps..

Download report from jsreport and angularjs

I'd like to know how could I make a report downloadable from my AngularJS Application?
The report is a .xlsx I can post the data, but the response is:
What I'd like is a downloadable file, or to open the .xlsx on Excel Online in other tab as in the preview.
How could I do that?
I usually recommend to create a hidden form and do plain http submit to jsreport /api/report. This is the most stable way and works across all browsers.
<form method='POST' target='_blank' action='/api/report' id='jsrForm'>
<input hidden='true' name='template[shortid]' value="41ucBgXKe"/>
<input hidden='true' name='data[foo]' value="Hello world"/>
<input hidden='true' name='options[Content-Disposition]' value="attachment; filename=myreport.pdf"/>
</form>
<script>
document.getElementById("jsrForm").submit();
</script>
Do you have control over the response? If so, add the content-disposition header and MediaType header to the response:
For System.Net.Http.HttpResponseMessage
var response = new HttpResponseMessage{Content = ...........}
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
FileName = "mydoc.xlsx"
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
For System.Net.WebClient
var client = new WebClient();
client.Headers.Add("Content-disposition", "attachment");
client.Headers.Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

Redirection with play! 2 scala after a post with angularJs

So far I used the usual method to post a form and redirect to the page I wanted to display like this :
The HTML part :
<form name="createArtistForm" method="post" action="/admin/createArtist">
Nom de l'artiste : <input type="text" name="artistName">
<input type="submit" value="Valider"/>
</form>
And the Scala part :
val artistBindingForm = Form(mapping(
"artistName" -> nonEmptyText(2)
)(Artist.formApply)(Artist.formUnapply)
)
def createArtist = Action { implicit request =>
artistBindingForm.bindFromRequest().fold(
formWithErrors => BadRequest(formWithErrors.errorsAsJson),
artist => {
artistId = Artist.saveArtist(artist)
Redirect(routes.ArtistController.artist(artistId))
}
)
}
And it worked fine, but now, the front end part of my app is managed by AngularJs so I submit the form with its http service like this :
$http.post('/admin/createArtist', {artistName : $scope.artiste.name})
The new artist is still well saved in my database, but the redirection has no effect.
What should I do in order to make the redirection work ? What am I missing ?
What I use to do in this cases is receive the result of the operation (error or success) and in case of success, redirect on the front end side with js (location = url).

Uploading a file to google drive from appengine (python)

I'm trying to upload a file to google drive from google app engine.
I have tried 2 different ways but I lose information in both.
The first one is the next one:
-The html form:
<html><body><form id='myForm' method='post' action='/guardar'
enctype='multipart/form-data' >
<input type="file" id="doc" name="doc" >
<input type="submit" value="Enviar"></form>
</body></html>
-The python code:
class guardar(webapp.RequestHandler):
#decorator.oauth_required
def post(self):
http = decorator.http()
service = build('drive', 'v2', http=http)
thefile = self.request.get('doc')
media_body = MediaInMemoryUpload(thefile, mimetype='text/plain', resumable=True)
response = service.files().insert(body={'title': 'prueba_si','mimeType': 'text/plain'},media_body=media_body).execute()
This way I lose the mimetype of the uploaded file and the title too; and I need both.
I have tried this other way but it always says that such file does not exist:
-The html file:
<html><body><form id='myForm' method='post' action='/guardar' >
<input type="file" id="doc" name="doc" >
<input type="submit" value="Enviar"></form>
</body></html>
-The python code:
class guardar(webapp.RequestHandler):
#decorator.oauth_required
def post(self):
http = decorator.http()
service = build('drive', 'v2', http=http)
thefile = self.request.get('doc')
mime_type=mimetypes.guess_type(thefile,strict=True)
media_body = MediaFileUpload(filename, mimetype=mime_type, resumable=True)
response = service.files().insert(body={'title': 'prueba_si','mimeType': mime_type},media_body=media_body).execute()
Thanks a lot for the help!
You don't need to pass the mime type in the media upload and also in the metadata. I would leave it just in the media upload.
You should not lose the title information, but I cannot reproduce your error.

Resources