import de.upw.ps.ucg.attachments.AttachmentService;
import de.upw.ps.ucg.attachments.model.Attachment;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.Iterator;
import java.util.UUID;
/**
* Created by IntelliJ IDEA.
* User: cdutz
* Date: 17.02.2010
* Time: 21:15:20
*/
public
class AttachmentUploadController
implements Controller, InitializingBean
{
private AttachmentService attachmentService;
private File attachmentsHomePath;
//////////////////////////////////////////////
// Spring setters.
//////////////////////////////////////////////
@Required
public
void setAttachmentsService(final AttachmentService aAttachmentService)
{
attachmentService = aAttachmentService;
}
@Required
public void setAttachmentsHomePath(File attachmentsHomePath) {
this.attachmentsHomePath = attachmentsHomePath;
}
//////////////////////////////////////////////
// Spring lifecycle methods.
//////////////////////////////////////////////
@Override
public void afterPropertiesSet() throws Exception {
if(!attachmentsHomePath.exists()) {
if(!attachmentsHomePath.mkdirs()) {
throw new Exception("Could not create attachment-directory specified by " +
"attachmentsHomePath property. '" + attachmentsHomePath.getAbsolutePath() +
"'");
}
}
if(!attachmentsHomePath.isDirectory()) {
throw new Exception("attachmentsHomePath must point to a directory. '" +
attachmentsHomePath.getAbsolutePath() + "'");
}
}
//////////////////////////////////////////////
// Controller methods.
//////////////////////////////////////////////
@Override
public
ModelAndView handleRequest(final HttpServletRequest aHttpServletRequest,
final HttpServletResponse aHttpServletResponse)
throws Exception
{
final String fileName = aHttpServletRequest.getParameter("fileName");
if(fileName != null) {
final MultipartHttpServletRequest mpHttpRequest = (MultipartHttpServletRequest) aHttpServletRequest;
final Iterator<String> fileParameterNames = mpHttpRequest.getFileNames();
while(fileParameterNames.hasNext()) {
final String fileParameterName = fileParameterNames.next();
final MultipartFile file = mpHttpRequest.getFile(fileParameterName);
final String id = saveAttachment(file);
if(id != null) {
final Attachment attachment = new Attachment();
attachment.setId(id);
attachment.setFileName(fileName);
attachment.setAdditionDate(Calendar.getInstance());
attachmentService.createAttachment(attachment);
return new ModelAndView("attachmentView", "attachment", attachment);
}
}
}
return null;
}
private String saveAttachment(MultipartFile file) {
// Generate a new Id for the attachment.
final UUID id = UUID.randomUUID();
// To limit the number of files in one directory, the hash of the id is used
// to partition the files into 32 containers.
final int containerId = Math.abs(id.hashCode()) % 32;
final File containerPath = new File(attachmentsHomePath, Integer.toString(containerId));
if(!containerPath.exists()) {
if(!containerPath.mkdirs()) {
throw new RuntimeException("Could not create container-path '" +
containerPath.getAbsolutePath() + "'");
}
}
// Save the file to the attachment directory.
final File attachmentPath = new File(containerPath, id.toString());
try {
file.transferTo(attachmentPath);
} catch (IOException e) {
throw new RuntimeException("Error saving attachment to attachment directory. '" +
attachmentPath.getAbsolutePath() + "'");
}
return id.toString();
}
}
The view:/**
* Created by IntelliJ IDEA.
* User: cdutz
* Date: 17.02.2010
* Time: 21:28:56
*/
public
class AttachmentView
extends AbstractView
{
private static final SimpleDateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
public AttachmentView() {
setContentType("application/octet-stream");
}
@Override
@SuppressWarnings("unchecked")
protected
void renderMergedOutputModel(final Map map,
final HttpServletRequest httpServletRequest,
final HttpServletResponse httpServletResponse)
throws Exception
{
if(map.containsKey("attachment")) {
final Attachment attachment = (Attachment) map.get("attachment");
httpServletResponse.getOutputStream().write(("attachmentId=" +
attachment.getId() + "\n").getBytes());
httpServletResponse.getOutputStream().write(("attachmentFileName=" +
attachment.getFileName() + "\n").getBytes());
httpServletResponse.getOutputStream().write(("attachmentAdditionDate=" +
isoDateFormat.format(attachment.getAdditionDate().getTime()) + "\n").getBytes());
}
else if(map.containsKey("file")) {
final Map<String, Object> model = (Map<String, Object>) map.get("model");
final Attachment attachment = (Attachment) model.get("attachment");
final File attachmentFile = (File) model.get("file");
if((attachment != null) && (attachmentFile != null)) {
setContentType("application/octet-stream");
final byte[] attachmentData = getBytesFromFile(attachmentFile);
httpServletResponse.getOutputStream().write(attachmentData);
}
}
}
protected
byte[] getBytesFromFile(final File aFile)
{
byte[] bytes = null;
InputStream is = null;
try {
is = new FileInputStream(aFile);
// Get the size of the file
final long length = aFile.length();
if (length < Integer.MAX_VALUE) {
// Create the byte array to hold the data
bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
}
} catch (final FileNotFoundException e) {
e.printStackTrace();
} catch (final IOException e) {
e.printStackTrace();
} finally {
// Close the input stream and return bytes
try {
if(is != null) {
is.close();
}
} catch (IOException e) {
// Well ... I guess we can't do anything against this, can we?
}
}
return bytes;
}
}
And the spring configuration: <!--
Dispatch requests to components registered by the
BeanNameUrlHandlerMapping class.
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--
View resolver used connect the views returned by
controllers to view implementation classes
-->
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<!--
Enable multipart message handling.
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- the maximum file size in bytes (Set to 100MB) -->
<property name="maxUploadSize" value="100000000"/>
</bean>
<!--
MVC Definitions
-->
<bean name="/attachment-upload.html" class="de.upw.ps.ucg.attachments.mvc.AttachmentUploadController">
<property name="attachmentsService" ref="attachmentsService"/>
<property name="attachmentsHomePath" value="${ucg.home}${file.separator}attachments"/>
</bean>
<bean id="attachmentView" class="de.upw.ps.ucg.attachments.mvc.AttachmentView"/>
Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.
Have a better answer? Share it in a comment.
From novice to tech pro — start learning today.
The Flex Client uploads the file to a http-url. The spring MVCController intercepts this and ueses the BeanNameUrlHandlerMapping to identify the controller by matching the url-suffix to a bean name (in my case it was "/attachment-upload.html")
Hope you get the idea ... it's a pretty tricky setup, it took me about one week to have everything up and running, but now it works great and if I follow my setup-template it's easy to reproduce.