1

我有一个 Spring MVC 注释驱动的项目,它运行良好。在这一点上,我的许多表单都很小,我倾向于使用 Ajax 请求来处理它们。我一直在使用这个插件: http: //jquery.malsup.com/form/来处理我的 Ajax 请求,它也一直运行良好。我遇到了一个问题。我正在使用 Jackson 将我的 @ResponseBody 项目序列化为 json。它工作得很好,但我遇到了需要上传文件的第一个表单。AjaxForm 在较旧的浏览器上使用 iframe 提交技巧来处理这个问题,但警告说有必要用<textarea></textarea>以确保所有信息都顺利到达。我一直在疯狂地环顾四周,我发现我可以为我的对象制作一个自定义序列化程序,但我想不出这将如何让我检查请求类型是否是XHR,然后才用<textarea></textarea>标签包围响应。有任何想法吗?

这是我的一些代码:

    public @ResponseBody
    JsonResponse setReferenceNumber(@ModelAttribute("referenceNumber") 
    @Valid ReferenceNumberBean referenceNumber, 
    BindingResult result, 
    HttpServletResponse response)
    {
      //Do some stuff
      //Theoretically here I would call upon some logic to surround the response?
      return jsonResponse;
    }

提前致谢!

更新——我几乎认为我已经解决了这个问题,特别是通过在 Spring 中添加一个新的拦截器:

    <mvc:interceptors>
      <bean class="edge.portal.vendor.web.interceptor.MultipartAjaxInterceptor"></bean>
    </mvc:interceptors>

然后进行拦截器测试以查看 X-Requested-with,然后添加标签,如果我的 javascript 已将调用标记为 Ajax 但标头未反映此更改,因此暗示 iframe ajax 帖子:

    @Component
    public class MultipartAjaxInterceptor extends HandlerInterceptorAdapter
    {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    {
    if(request.getParameter("isAjax") != null && request.getHeader("X-Requested-With") == null)
        response.getWriter().write("<textarea>");

    return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
       {
       if(request.getParameter("isAjax") != null && request.getHeader("X-Requested-With") == null)
           response.getWriter().write("</textarea>");
       }
    }

现在显然我遇到的问题是你不能多次调用响应的 getWriter 或 OutputStream,我觉得我在解决这个问题的正确轨道上,但不知道从哪里开始。

4

3 回答 3

1

让我发布一下,我是如何解决这个问题的(我不知道,是否正确)。我在前端使用 Dojo,而 Dojodojo.io.iframe.send用于文件上传。处理表单 post 的 JS 函数如下。(看handleAs我设置的“”属性为' json')

function ioIframeGetJson(){
    var td = dojo.io.iframe.send({
        url: "${pageContext. request. contextPath}/switch/add",
        form: "frmSwitchTypeAdd",
        method: "post",
        preventCache: true, 
        handleAs: "json",
         load: function(response, ioArgs){
                clearSwitchTypeForm();
            },

            error: function(response, ioArgs){
            }
    });
}

在我的情况下,处理表单提交的控制器方法,其中还包括上传的文件,如下所示,(看我将返回类型保留为字符串)

@RequestMapping(value="/add",method=RequestMethod.POST)
    @ResponseBody
    public String add(HttpServletRequest request) {
        . . . . .
        //I call the toString method of the model I want to return in Response
        return fromModel(switchType).toString();
}

toString()方法编码如下,我让Json字符串被包围<textarea>

public String toString() {
        return "<textarea>{name:'" + name + "', code:'" + code
                + "', className:'" + className + "', dynamic:" + dynamic+"}</textarea>";
    }
于 2012-06-15T06:25:55.983 回答
1

我知道在这里回答有点晚了,但我最近遇到了类似的问题,我想分享我的结果。您使用 HandlerInterceptor 走在正确的轨道上,但您应该使用 getOutputStream() 方法而不是 getWriter() 方法。根据ServletReponse 的Javadoc

getOutputStream

Throws:
IllegalStateException - if the getWriter method has been called on this response

类似地,如果 getOutputStream 已经被调用,getWriter 方法将抛出 IllegalStateException,但只要另一个从未被调用,每一个都可以多次。Jackson 在写入 JSON 数据时似乎使用了 getOutputStream。因此,您的代码应使用以下修改:

@Component
public class MultipartAjaxInterceptor extends HandlerInterceptorAdapter
{
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(request.getParameter("isAjax") != null && request.getHeader("X-Requested-With") == null)
            response.getOutputStream().write("<textarea>".getBytes(response.getCharacterEncoding()));

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
       if(request.getParameter("isAjax") != null && request.getHeader("X-Requested-With") == null)
           response.getOutputStream().write("</textarea>".getBytes(response.getCharacterEncoding()));
    }
}

如果响应最初是作为“application/json”发送的,那么使用 postHandle 中的 setContentType 方法更改响应的内容类型也可能会有所帮助。

于 2014-07-23T23:37:27.563 回答
0

所以这是我得到的答案,它类似于 Ravi 的答案,但对我的设置来说似乎更好一些。首先是将我@ResponseBody的 's 更改为字符串。这是假设我将手动使用<textarea />标签围绕响应完成的。然后我创建了一个名为的新类JsonResponseSerializer,如下所示:

public class JsonResponseSerializer
{
private HttpServletRequest request;

public JsonResponseSerializer(HttpServletRequest request)
{
    this.request = request;
}

public String serialize(JsonResponse jsonResponse) throws IOException
  {
    String response = "";

    ObjectMapper mapper = new ObjectMapper();

    response = mapper.writeValueAsString(jsonResponse);

    if(request.getParameter("isAjax") != null && request.getHeader("X-Requested-With") == null)
    {
        response = "<textarea>" + response + "</textarea>";
    }

    return response;
  }
}

然后我将我的回复的返回语句更改为:

    return new JsonResponseSerializer(request).serialize(jsonResponse);

本质上,我创建了一个实用方法,它注入了 ServletRequest,然后简单地要求 Jackson 序列化对象,然后在<textarea />必要时将其包围。

于 2012-06-15T17:18:21.627 回答