【问题标题】:Spring MVC 3 - Jackson - AjaxFormSpring MVC 3 - 杰克逊 - AjaxForm
【发布时间】:2012-06-17 18:21:04
【问题描述】:

我有一个 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,我觉得我在解决这个问题的正确轨道上,但不知道从哪里开始。

【问题讨论】:

    标签: json spring-mvc jackson ajaxform


    【解决方案1】:

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

    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 方法更改响应的内容类型也可能会有所帮助。

    【讨论】:

      【解决方案2】:

      让我发布一下,我是如何解决这个问题的(我不知道,是否正确) . 我在前端使用 Dojo,Dojo 使用dojo.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字符串用&lt;textarea&gt;包围

      public String toString() {
              return "<textarea>{name:'" + name + "', code:'" + code
                      + "', className:'" + className + "', dynamic:" + dynamic+"}</textarea>";
          }
      

      【讨论】:

      • 我可能最终不得不这样做,我希望我仍然能够使用 JsonSerializer,因为它非常有用,但似乎这可能不是一个选择。
      【解决方案3】:

      所以这是我得到的答案,它与 Ravi 的答案相似,但对我的设置来说似乎更好一些。首先是将我的@ResponseBody 更改为字符串。这是假设我将使用&lt;textarea /&gt; 标签手动包围响应。然后我创建了一个名为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 序列化对象,然后在必要时用 &lt;textarea /&gt; 包围它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-24
        • 2012-09-10
        • 2014-08-06
        相关资源
        最近更新 更多