2012-06-14 86 views
1

我有一个Spring MVC注释驱动的项目,它工作的很棒。在这一点上,我的很多表单都很小,我很容易使用Ajax请求来处理它们。我一直在使用这个插件:http://jquery.malsup.com/form/来处理我的Ajax请求,并且它一直在很好地工作。尽管我遇到了问题。我正在使用Jackson将我的@ResponseBody项目序列化为json。它工作得很好,但我遇到了我需要上传文件的第一个表单。 AjaxForm使用iframe提交技巧在较旧的浏览器上处理此操作,但警告必须将您的响应与<textarea></textarea>包围起来,以确保所有信息都能成功到达。我一直在疯狂地环视四周,我发现我可以为我的对象制作一个自定义序列化器,但我想不出如何让我检查请求类型是否为XHR,然后只用环绕响应的<textarea></textarea>标签。有任何想法吗?Spring MVC 3 - Jackson - AjaxForm

下面是我的一些代码:提前

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; 
    } 

谢谢!

UPDATE - 我几乎以为我已经解决了这一问题,特别是在春季增加一个新的拦截器:

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

然后不得不看的拦截试验,如果X-要求,有,然后添加标签,如果我的javascript已标记的呼叫作为阿贾克斯,但头部没有反映这种变化,从而暗示的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>"); 
     } 
    } 

现在很明显,我跑进问题是,你不能CAL l响应的getWriter或OutputStream不止一次,我觉得我正处在解决这个问题的正确轨道上,但不知道从哪里开始。

回答

1

我知道这里的答案有点迟,但我最近有类似的问题,我想分享我的结果。您处在HandlerInterceptor的正确轨道上,但您应该使用getOutputStream()方法而不是getWriter()方法。按照Javadoc for ServletReponse

getOutputStream 

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

同样,的getWriter方法将抛出IllegalStateException异常,如果getOutputStream方法已经被调用,但每个人可以多次,只要对方永远不会被调用。 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())); 
    } 
} 

这也可能是有益的通过使用的postHandle该方法的setContentType如果响应为“应用/ JSON”最初发送到改变响应的内容类型。

1

让我发帖,我如何解决这个问题(我不知道,是否正确) 。 我在前端使用Dojo,Dojo使用dojo.io.iframe.send进行文件上传。处理表单的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>"; 
    } 
+0

我可能最终不得不这样做,我希望我仍然能够使用JsonSerializer,因为它非常有用,但它似乎可能不是一个选项。 – Mark

0
包围

所以这里是我到达的答案,它类似于拉维的答案,但似乎我的设置好一点。首先是将我的@ResponseBody改为Strings。假设我将用<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中的实用工具方法然后注入,然后简单地要求杰克逊序列化该对象,然后在必要时用<textarea />包围它。