1

我有一个表单,允许用户输入几个字段并上传两个单独的文件。在上传每个文件时,都会向服务器发送一个请求以检索文件并构建显示。一旦用户对显示看起来不错感到满意,他们就可以将新数据提交到数据库。

我遇到的问题是 Spring-MVC 似乎在最后一次调用服务器时丢失了会话对象。我需要它来保留会话,直到我明确告诉它使用 SessionStatus 删除对象。

这是我的控制器类的代码:

package com.mbn.modeldisplay.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;

import com.mbn.modeldisplay.pojo.CandidateModel;
import com.mbn.modeldisplay.pojo.Model;
import com.mbn.modeldisplay.service.IModelService;
import com.mbn.modeldisplay.service.ServiceException;
import com.mbn.modeldisplay.util.TempFileManager;

@SessionAttributes(value = { "candidateModel" })
@Controller
@RequestMapping("/model/*")
public class ModelHandler {

    protected static Logger log = LoggerFactory.getLogger(ModelHandler.class);
    protected IModelService modelService = null;

    private static final String DEFAULT_TEMPLATE_TEXTURE = "/assets/defaultimage.png";
    private static final String CANDIDATE_MODEL_NAME = "candidateModel";

    @ModelAttribute(CANDIDATE_MODEL_NAME)
    public CandidateModel createCandidate() {
        CandidateModel candidate = new CandidateModel();
        log.debug("createCandidate returning: " + candidate);
        log.debug("\n\n");
        return candidate;
    }

    @RequestMapping(method = RequestMethod.GET)
    public String startEditModel(
            @RequestParam(value = "modelId", required = false) String modelId,
            @ModelAttribute CandidateModel candidate) {

        try {
            Model m = modelService.read(modelId);
            if (null == m) {
                m = new Model();
                m.modelId = modelId;
            }

            candidate.setOriginal(m);
            log.debug("startEditModel returning: " + candidate);
        } catch (ServiceException se) {
            log.error("Unable to access datastore", se);
        }
        log.debug("\n\n");
        return "ModelEdit";
    }

    @RequestMapping(value = "register/binary", method = RequestMethod.POST)
    public String addModel(@RequestParam MultipartFile model,
            @ModelAttribute(CANDIDATE_MODEL_NAME) CandidateModel tempCandidate) {

        log.debug("addModel received: " + tempCandidate);
        try {
            File tempFile = tempCandidate.getCandidateModelFile();
            if (null != tempFile) {
                log.debug("Remove previous candidate: "
                        + tempFile.getAbsolutePath());
                tempFile.delete();
            }

            tempFile = TempFileManager.getTempFile(
                    "norrim01",
                    "ModelDisplay",
                    model.getOriginalFilename().substring(
                            model.getOriginalFilename().lastIndexOf('.')));
            log.debug("Writing to temp file: " + tempFile.getAbsolutePath());

            InputStream is = model.getInputStream();
            FileOutputStream fw = new FileOutputStream(tempFile);
            byte[] buffer = new byte[1024];

            int read;
            while (-1 != (read = is.read(buffer))) {
                fw.write(buffer, 0, read);
            }

            fw.flush();
            fw.close();

            tempCandidate.setCandidateModelFile(tempFile);

        } catch (Exception e) {
            log.error("Unable to process model file candidate.", e);

            return "ErrorPage";
        }
        log.debug("\n\n");
        return "ModelEdit";
    }

    @RequestMapping(value = "register/binary", method = RequestMethod.GET)
    public void getCandidateModel(HttpServletResponse response,
            @ModelAttribute(CANDIDATE_MODEL_NAME) CandidateModel tempCandidate)
            throws Exception {
        log.debug("getCandidateModel received: " + tempCandidate);

        File tempFile = tempCandidate.getCandidateModelFile();
        if (null == tempFile || !tempFile.exists()) {
            throw new FileNotFoundException("Candidate Model File");
        }

        log.debug("register/binary returning " + tempFile.getAbsolutePath());

        response.setContentType("application/octet-stream");
        response.setHeader(
                "Content-Disposition",
                "attachment; filename=candidatemodel"
                        + tempFile.getName().substring(
                                tempFile.getName().lastIndexOf('.')));

        InputStream is = new FileInputStream(tempFile);
        OutputStream fw = response.getOutputStream();
        byte[] buffer = new byte[1024];

        int read;
        while (-1 != (read = is.read(buffer))) {
            fw.write(buffer, 0, read);
        }
        log.debug("\n\n");
        fw.flush();
    }

    @RequestMapping(value = "register/template", method = RequestMethod.POST)
    public String addTemplate(@RequestParam MultipartFile template,
            @ModelAttribute(CANDIDATE_MODEL_NAME) CandidateModel tempCandidate)
        throws Exception {
        log.debug("addTemplate received: " + tempCandidate);
        try {
            File tempFile = tempCandidate.getCandidateTemplateFile();
            if (null != tempFile) {
                log.debug("Remove previous candidate: "
                        + tempFile.getAbsolutePath());
                tempFile.delete();
            }

            tempFile = TempFileManager.getTempFile(
                    "norrim01",
                    "ModelDisplay",
                    template.getOriginalFilename().substring(
                            template.getOriginalFilename().lastIndexOf('.')));
            log.debug("Writing to temp file: " + tempFile.getAbsolutePath());

            InputStream is = template.getInputStream();
            FileOutputStream fw = new FileOutputStream(tempFile);
            byte[] buffer = new byte[1024];

            int read;
            while (-1 != (read = is.read(buffer))) {
                fw.write(buffer, 0, read);
            }

            fw.flush();
            fw.close();

            tempCandidate.setCandidateTemplateFile(tempFile);
        } catch (Exception e) {
            log.error("Unable to process model file candidate.", e);

            return "ErrorPage";
        }
        log.debug("\n\n");

        return "ModelEdit";
    }

    @RequestMapping(value = "register/template", method = RequestMethod.GET)
    public void getCandidateTemplate(
            @ModelAttribute(CANDIDATE_MODEL_NAME) CandidateModel tempCandidate,
            HttpSession session, HttpServletResponse response) throws Exception {
        log.debug("getCandidateTemplate received: " + tempCandidate);
        File tempFile = tempCandidate.getCandidateTemplateFile();
        log.debug("register/template found in session: " + tempFile);
        if (null == tempFile || !tempFile.exists()) {
            String location = session.getServletContext().getRealPath(
                    DEFAULT_TEMPLATE_TEXTURE);
            if (null != location)
                tempFile = new File(location);
            else
                throw new FileNotFoundException(
                        "Unable to locate the default template texture");
        }

        log.debug("register/template returning " + tempFile.getAbsolutePath());

        response.setContentType("application/octet-stream");
        response.setHeader(
                "Content-Disposition",
                "attachment; filename=candidatetemplate"
                        + tempFile.getName().substring(
                                tempFile.getName().lastIndexOf('.')));

        InputStream is = new FileInputStream(tempFile);
        OutputStream fw = response.getOutputStream();
        byte[] buffer = new byte[1024];

        int read;
        while (-1 != (read = is.read(buffer))) {
            fw.write(buffer, 0, read);
        }

        fw.flush();

        log.debug("\n\n");
    }

    /**
     * @return the modelService
     */
    public IModelService getModelService() {
        return modelService;
    }

    /**
     * @param modelService
     *            the modelService to set
     */
    @Autowired
    public void setModelService(IModelService modelService) {
        this.modelService = modelService;
    }

}

模型文件上传并使用 GET 请求正确检索到相同的 URL,图形文件也正确上传到/register/templateURL 并添加到 CandidateModel 会话对象,但是当register/template发出 GET 时,Spring-MVC 会创建一个新的,空 CandidateModel 对象,我无法检索上传的图形,从调试输出中可以看出,这里:

2013-09-11 11:58:10,078 DEBUG  [ModelHandler] addModel received: CandidateModel [original=null, candidateModelFile=null, candidateTemplateFile=null, object Id=com.mbn.modeldisplay.pojo.CandidateModel@1c6cc9c] 
2013-09-11 11:58:10,216 DEBUG  [ModelHandler] Writing to temp file: C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim011291263503728127085.obj 
2013-09-11 11:58:10,221 DEBUG  [ModelHandler] 


2013-09-11 11:58:10,398 DEBUG  [ModelHandler] getCandidateModel received: CandidateModel [original=null, candidateModelFile=C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim011291263503728127085.obj, candidateTemplateFile=null, object Id=com.mbn.modeldisplay.pojo.CandidateModel@1c6cc9c] 
2013-09-11 11:58:10,398 DEBUG  [ModelHandler] register/binary returning C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim011291263503728127085.obj 
2013-09-11 11:58:10,400 DEBUG  [ModelHandler] 


2013-09-11 11:58:10,460 DEBUG  [ModelHandler] createCandidate returning: CandidateModel [original=null, candidateModelFile=null, candidateTemplateFile=null, object Id=com.mbn.modeldisplay.pojo.CandidateModel@3c7038b9] 
2013-09-11 11:58:10,460 DEBUG  [ModelHandler] 


2013-09-11 11:58:10,463 DEBUG  [ModelHandler] getCandidateTemplate received: CandidateModel [original=null, candidateModelFile=null, candidateTemplateFile=null, object Id=com.mbn.modeldisplay.pojo.CandidateModel@3c7038b9] 
2013-09-11 11:58:10,463 DEBUG  [ModelHandler] register/template found in session: null 
2013-09-11 11:58:10,464 DEBUG  [ModelHandler] register/template returning C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\webapps\ModelDisplay\assets\defaultimage.png 
2013-09-11 11:58:10,465 DEBUG  [ModelHandler] 


2013-09-11 11:58:15,426 DEBUG  [ModelHandler] addTemplate received: CandidateModel [original=null, candidateModelFile=C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim011291263503728127085.obj, candidateTemplateFile=null, object Id=com.mbn.modeldisplay.pojo.CandidateModel@1c6cc9c] 
2013-09-11 11:58:15,604 DEBUG  [ModelHandler] Writing to temp file: C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim01647051706271088553.PNG 
2013-09-11 11:58:15,986 DEBUG  [ModelHandler] 


2013-09-11 11:58:16,014 DEBUG  [ModelHandler] getCandidateModel received: CandidateModel [original=null, candidateModelFile=C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim011291263503728127085.obj, candidateTemplateFile=C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim01647051706271088553.PNG, object Id=com.mbn.modeldisplay.pojo.CandidateModel@1c6cc9c] 
2013-09-11 11:58:16,015 DEBUG  [ModelHandler] register/binary returning C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\temp\norrim011291263503728127085.obj 
2013-09-11 11:58:16,016 DEBUG  [ModelHandler] 


2013-09-11 11:58:16,117 DEBUG  [ModelHandler] createCandidate returning: CandidateModel [original=null, candidateModelFile=null, candidateTemplateFile=null, object Id=com.mbn.modeldisplay.pojo.CandidateModel@1ae73783] 
2013-09-11 11:58:16,118 DEBUG  [ModelHandler] 


2013-09-11 11:58:16,119 DEBUG  [ModelHandler] getCandidateTemplate received: CandidateModel [original=null, candidateModelFile=null, candidateTemplateFile=null, object Id=com.mbn.modeldisplay.pojo.CandidateModel@1ae73783] 
2013-09-11 11:58:16,119 DEBUG  [ModelHandler] register/template found in session: null 
2013-09-11 11:58:16,119 DEBUG  [ModelHandler] register/template returning C:\Users\Michael Norris\Development\Tomcat\apache-tomcat-7.0.29\webapps\ModelDisplay\assets\defaultimage.png 
2013-09-11 11:58:16,121 DEBUG  [ModelHandler] 

我的观点是使用 JQuery 和 Ajax 在文件被选中后立即发送文件。如果结果成功,showCandidateModel则使用 THREE.js 中的例程查询服务器以检索文件。以下是选择文件后立即发生的上传示例:

if (formdata) {
            $.ajax({
                url: "/ModelDisplay/rest/model/register/binary",
                type: "POST",
                data: formdata,
                processData: false,
                contentType: false,
                success: function (res) {
                    showCandidateModel(); 
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    document.getElementById("response").innerHTML = 
                        "<h2>" + textStatus + "</h2><BR><BR><p>" + errorThrown + "<p>"; 
                }
            });
        }

我还尝试将对象添加到处理程序方法并直接使用andHttpSession与之交互,但它表现出相同的行为,让我相信 Spring-MVC 实际上并没有使用来自 Tomcat 的真实会话对象,而是使用它的其他一些实现管理。addAttributegetAttribute

为了完整起见,这是我的 Spring 配置:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">


  <!-- the application context definition for the springapp DispatcherServlet -->
  <bean id="mongoDBDatabaseName" class="java.lang.String">
    <constructor-arg value="ModelDisplay"/>
  </bean>

  <bean id="mongoDBDatabaseHost" class="java.lang.String">
    <constructor-arg value="localhost"/>
  </bean>

  <bean id="mongoDBDatabasePort" class="java.lang.Integer">
    <constructor-arg value="27017"/>
  </bean>

  <bean id="mongoDB" class="com.mbn.modeldisplay.dao.ModelDisplayMongoDB">
    <constructor-arg ref="mongoDBDatabaseName"/>
    <constructor-arg ref="mongoDBDatabaseHost"/>
    <constructor-arg ref="mongoDBDatabasePort"/>
  </bean>

  <context:component-scan base-package="com.mbn.modeldisplay"/>

  <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
      <property name="prefix" value="/"></property>
      <property name="suffix" value=".jsp"></property>        
  </bean>

  <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
      <!-- one of the properties available; the maximum file size in bytes -->
      <property name="maxUploadSize" value="100000000"/>
  </bean>

</beans>

这是我的依赖:

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>3.2.4.RELEASE</version>
</dependency>

我已经搜索了示例,我发现许多示例显示了单个文件的上传和多个文件的上传示例,但没有一个示例提供多个文件的多步上传。在此先感谢您的时间。

4

0 回答 0