Reputation: 10961
I'm trying to write a uploader for file and video in grails/groovy. So every time the user fills out a new form the controller uploads the file and saves the filename along with other fields into the database. So, here is the save procedure:
def save = {
def streamInstance = new Stream(params)
if(request){
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
CommonsMultipartFile uploadedFile = (CommonsMultipartFile)mpr.getFile("myFile");
if(!uploadedFile.empty){
println "helloworld"
println "Class: ${uploadedFile.class}"
println "Name: ${uploadedFile.name}"
println "OriginalFileName: ${uploadedFile.originalFilename}"
println "Size: ${uploadedFile.size}"
println "ContentType: ${uploadedFile.contentType}"
/*
//def webRootDir = servletContext.getRealPath("/")
//def userDir = new File(webRootDir, "/files/${session.user.login}")
//userDir.mkdirs()
uploadedFile.transferTo(new File("/Users/philipperibeiro/ctv/ctv/web-app/files"))
streamInstance.file = uploadedFile.originalFilename
*/
}
else{
flash.message = "file cannot be empty"
}
}
if(!streamInstance.hasErrors() && streamInstance.save(flush : true)){
flash.message = "${message(code: 'default.created.message', args : [message(code: 'stream.label', default:'Stream'), streamInstance.id])}"
redirect(action : "show", id : streamInstance.id)
}
else{
render(view : "create", model : [streamInstance : streamInstance])
}
}
I'm getting this error: Error 500: Executing action [save] of controller [ctv.StreamController] caused exception: Cannot cast object 'org.apache.catalina.core.ApplicationHttpRequest@19f46c5d' with class 'org.apache.catalina.core.ApplicationHttpRequest' to class 'org.springframework.web.multipart.MultipartHttpServletRequest' Servlet: grails URI: /ctv/grails/stream/save.dispatch Exception Message: Cannot cast object 'org.apache.catalina.core.ApplicationHttpRequest@19f46c5d' with class 'org.apache.catalina.core.ApplicationHttpRequest' to class 'org.springframework.web.multipart.MultipartHttpServletRequest' Caused by: Cannot cast object 'org.apache.catalina.core.ApplicationHttpRequest@19f46c5d' with class 'org.apache.catalina.core.ApplicationHttpRequest' to class 'org.springframework.web.multipart.MultipartHttpServletRequest' Class: StreamController At Line: [22] Code Snippet:
could someone give a clue of who to fix it?
<%@ page import="ctv.Stream" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'stream.label', default: 'Stream')}" />
<title><g:message code="default.create.label" args="[entityName]" /></title>
<jqfu:resources tmpl=”false” />
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></span>
<span class="menuButton"><g:link class="list" action="list"><g:message code="default.list.label" args="[entityName]" /></g:link></span>
</div>
<div class="body">
<h1><g:message code="default.create.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${streamInstance}">
<div class="errors">
<g:renderErrors bean="${streamInstance}" as="list" />
</div>
</g:hasErrors>
<g:form action="save" >
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="district"><g:message code="stream.district.label" default="District" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'district', 'errors')}">
<g:select name="district.id" from="${ctv.District.list()}" optionKey="id" value="${streamInstance?.district?.id}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="dateAdded"><g:message code="stream.dateAdded.label" default="Date Added" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'dateAdded', 'errors')}">
<g:datePicker name="dateAdded" precision="day" value="${streamInstance?.dateAdded}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="name"><g:message code="stream.name.label" default="Name" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'name', 'errors')}">
<g:textField name="name" maxlength="30" value="${streamInstance?.name}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="description"><g:message code="stream.description.label" default="Description" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'description', 'errors')}">
<g:textField name="description" maxlength="100" value="${streamInstance?.description}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="media"><g:message code="stream.media.label" default="Media" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'media', 'errors')}">
<g:textField name="media" maxlength="30" value="${streamInstance?.media}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="file"><g:message code="stream.file.label" default="File" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'file', 'errors')}">
<!--g:textField name="file" maxlength="30" value="${streamInstance?.file}" />-->
<g:form action="save" enctype="multipart/form-data">
<input type="file" name="myFile" />
</g:form>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="logo"><g:message code="stream.logo.label" default="Logo" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'logo', 'errors')}">
<g:textField name="logo" value="${streamInstance?.logo}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="published"><g:message code="stream.published.label" default="Published" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: streamInstance, field: 'published', 'errors')}">
<g:checkBox name="published" value="${streamInstance?.published}" />
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" /></span>
</div>
</g:form>
</div>
</body>
</html>
Upvotes: 3
Views: 17721
Reputation: 67
You are getting the exception
groovy.lang.MissingMethodException: No signature of method:
org.apache.catalina.core.ApplicationHttpRequest.getFile()
because you have not added enctype
the form should look like
<form action="action_name" method="POST" enctype="multipart/form-data">
Upvotes: 0
Reputation: 4851
Another way you can use Grails file upload plugin. See more information here http://grails.org/plugin/file-uploader. It has robust interface and provides rich abilities to make really nice part of your app.
Upvotes: 0
Reputation: 1970
The cause of the error message
The problem with your code is that you are casting the request object to the wrong class. This is the part of the error message that tells you this:
Cannot cast object 'org.apache.catalina.core.ApplicationHttpRequest@19f46c5d' with class 'org.apache.catalina.core.ApplicationHttpRequest' to class 'org.springframework.web.multipart.MultipartHttpServletRequest'
So you have an org.apache.catalina.core.ApplicationHttpRequest
and you're trying to cast it to a org.springframework.web.multipart.MultipartHttpServletRequest
which can't be done.
The beauty of groovy (which grails is written on) is that it is dynamically typed. So most of this casting is redundant anyway!
Try replacing these two lines
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
CommonsMultipartFile uploadedFile = (CommonsMultipartFile)mpr.getFile("myFile");
With this:
def uploadedFile = request.getFile( "myFile" )
But this will not solve your problem! It will just change the error message you get :'(
The root source of the problem, and how did we end up with the wrong request class?
Thinking about why you have the wrong request type for the cast, you might have forgotten to include enctype="multipart/form-data"
in your form action. It should probably look something like this:
<g:form action="save" method="post" enctype="multipart/form-data"> ... </g:form>
Just changing this might solve your problem, but I would definitely remove the casting too.
Update: the real(?) answer
In HTML (and GSPs are used to make HTML) you cannot have nested forms. One form cannot be inside another. Your GSP has two forms, the first looks like this:
<g:form action="save">
The second (the inside one) looks like this
<g:form action="save" enctype="multipart/form-data">
So you need to get rid of the inside one completely, and make sure the outside one (the only remaining one) looks like this:
<g:form action="save" method="post" enctype="multipart/form-data">
Upvotes: 8
Reputation: 2611
I think you may be over complicating this. All we are doing is
def image = request.getFile('image') // image is the parameter name
def imageBytes = image.getBytes()
You will want to check the mimeType as well.
Upvotes: 1