2012-07-19 79 views
0

对于新项目,我们在客户端使用jQuery组件,其中一个是blueImp文件上传器。我们正在愉快地编写代码,并且Chrome和Firefox中的所有工作都非常棒......直到有人试图在Internet Explorer中打开该网站。显然,在使用这个上传组件时,IE无法处理来自服务器的application/json返回 - 而且,它只是将其作为文件流式传输给用户。无论如何,很多用户确实有这个问题(在他们的网站上提到:https://github.com/blueimp/jQuery-File-Upload/wiki/Frequently-Asked-Questions和其他bug记者)@根据条件生成注释

但是,其中提到的大多数解决方法都基于PHP。我们在服务器端使用Java,更具体地说:JAX-RS。现在,JAX-RS拥有这个可爱的@Produces注释,这是......很好,很静态。我一直在挖掘文档,但没有明智之举。有什么办法可以给这个@Produces注释添加一个条件吗?要说清楚:我想在用户使用IE时返回文本/纯文本(或类似的东西),并在用户使用浏览器时返回application/json ... eeeerrrm,我的意思是一些OTHER浏览器:-)

谢谢!

+1

也许一个servlet过滤器可以改变IE的Accept头,然后JAX-RS可以在那里发送?或者为IE截取并重写JAX-RS输出的过滤器? – Thilo 2012-07-19 07:07:43

+0

您还可以通过diff @produces拥有两种不同的方法,然后解析为相同的方法。 – 2012-07-19 07:10:12

+0

哇,快速的答复,谢谢:-) @Thilo:接缝​​是可行的,虽然我真的不喜欢重写过滤器中的响应。但它似乎是需要考虑的事情。谢谢! – gjoris 2012-07-19 07:16:51

回答

1

我通过编写我自己的提供者(实际上是我在这里问这个问题之前开始做的事)来事后解决了这个问题。对于那些有兴趣(和现在还不知道):写自己的供应商包括两个步骤:

  • 加入@Provider到您的类,然后@Produces()
  • 实施MessageBodyWriter接口,覆盖了必要的方法

我的代码结束了:

package com.mypackage;  

import com.google.common.collect.Lists; 
import com.google.gson.Gson; 
import com.mypackage.UploadResponse; 

import javax.ws.rs.Produces; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.MultivaluedMap; 
import javax.ws.rs.ext.MessageBodyWriter; 
import javax.ws.rs.ext.Provider; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.io.OutputStreamWriter; 
import java.lang.annotation.Annotation; 
import java.lang.reflect.Type; 

@Produces("text/plain") 
@Provider 
public class UploadResponseProvider implements MessageBodyWriter<UploadResponse> { 
    @Override 
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 
     /* You could check the type here, or do some additional checks, but I can just return true, because if it is an UploadResponse (which is inferred via the generic), it's all ok */ 
     return true; 
    } 

    @Override 
    public long getSize(UploadResponse uploadResponse, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 
     return -1; 
    } 

    @Override 
    public void writeTo(UploadResponse uploadResponse, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { 
     OutputStreamWriter writer = new OutputStreamWriter(entityStream); 
     writer.write(new Gson().toJson(Lists.newArrayList(uploadResponse))); 
     writer.flush(); 
    } 

} 

只是为了解释这个代码一点点:UploadResponse是我的对象返回。这是一个简单的POJO,包含字段url,大小和名称,以及getter和setter。

我读过返回的文本/ plain使得blueImp jQuery Fileupload正常运行,所以这是一个用于UploadResponse的text/plain输出的Provider。

我在这里做的是创建一个JSON对象,把它放在一个列表中,并将该列表写入响应。我正在创建一个UploadResponses列表,因为我的UI期望。 blueImp文件上传预计,默认情况下,BTW。我们在JAX-RS上进行自动上传,并对1个文件进行硬性限制,所以我不必处理超过1个项目。在重新使用这些代码时要小心,它可能需要一些修改。

正如你所看到的,这就是我所做的一切,没有更多。其余的只是默认实现,因为在我的情况下,我不关心任何它。

小记:请勿关闭作者。只需冲洗它。在写入回复之前,关闭它将关闭它。

0

使用Servlet过滤器应该工作。这是一个(未经测试的):

package blah; 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

public class IEFixFilter implements Filter { 

    @Override 
    public void doFilter(ServletRequest req, 
         ServletResponse resp, 
         FilterChain chain) throws IOException, ServletException 
    { 
     chain.doFilter(req, resp); 

     String userAgent = ((HttpServletRequest) req).getHeader("User-Agent"); 
     if(userAgent.contains("MSIE")) { 
      response.setContentType("text/plain"); 
     } 
    } 

    @Override 
    public void init(FilterConfig cfg) throws ServletException {} 

    @Override 
    public void destroy() {} 
} 

并将您添加到web.xml中的配置。您需要将blah更改为您将上述类和url-pattern与您用于文件上传的url匹配的包。

<filter> 
    <filter-name>ieFixFilter</filter-name> 
    <filter-class>blah.IEFixFilter</filter-class> 
    </filter> 

    <filter-mapping> 
    <filter-name>ieFixFilter</filter-name> 
    <url-pattern>/upload/url/*</url-pattern> 
    </filter-mapping> 
+0

但是,如果响应已被提交,您可能无法再更改Content-Type标头。 – Thilo 2012-07-20 07:27:10

+0

好点。那总是让我感觉到。也许某些方面可能被用来做类似的事情,但在响应之前已经犯下了。 – theon 2012-07-20 08:15:28

+0

的确,Thilo是对的。我试图摆弄一个过滤器,但它没有解决,因为 - 正如已经说过的 - 响应已经被提交。 – gjoris 2012-07-21 10:12:34

0

这在这个晚期阶段可能没用,但我最近有这个确切的要求,这是一个相当简单的修复。假设您正在返回一个八位字节流,但如果出现问题,您只想返回纯JSON。

  1. 不要在您的宁静方法的声明中指定@Produces。
  2. 基于对你的方法会发生什么,你将要

    return Response.status(200).entity(file).type(MediaType.APPLICATION_OCTET_STREAM).build(); 
    

所以做这种事情,如果比如你需要一个JSON对象,而不是提前返回的octet-的流,然后只是做

return Response.status(500).entity(errorObject).type(MediaType.APPLICATION_JSON).build(); 

重要的是,当您建立响应时指出MediaType。

希望这可以帮助别人。