0

对于一个新项目,我们在客户端使用 jQuery 组件,其中之一是 blueImp 文件上传器。我们正在愉快地编写代码,并且在 Chrome 和 Firefox 中一切正常……直到有人试图在 Internet Explorer 中打开该站点。显然,在使用这个上传组件时,IE 无法处理从服务器返回的 application/json - 而且,它只是将其作为文件流式传输给用户。无论如何,很多用户确实有这个问题(在他们的网站上提到:https ://github.com/blueimp/jQuery-File-Upload/wiki/Frequently-Asked-Questions和他们的错误报告的其他地方)

但是,其中提到的大多数解决方法都是基于 PHP。我们在服务器端使用 Java,更具体地说:JAX-RS。现在,JAX-RS 有了这个可爱的 @Produces 注释,它是……嗯,非常静态。我一直在挖掘文档,但没有发现更明智的。有什么方法可以向这个 @Produces 注释添加条件吗?说清楚:当用户使用 IE 时,我想返回 text/plain(或类似的东西),当用户使用浏览器时,我想返回 application/json ...eeeerrrm,我的意思是,一些其他浏览器 :-)

谢谢!

4

3 回答 3

1

我最终通过编写自己的 Provider 解决了这个问题(这实际上是我在这里提出问题之前开始做的事情)。对于那些感兴趣(但还不知道)的人:编写自己的提供程序涉及 2 个步骤:

  • 将 @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。

我读到返回 text/plain 使 blueImp jQuery Fileupload 起作用,所以这是 UploadResponse 的 text/plain 输出的提供程序。

我在这里所做的是创建一个 JSON 对象,将其放入一个列表中,然后将该列表写入响应。我正在创建一个 UploadResponses 列表,因为我的 UI 期望这样做。blueImp File Upload 期望默认情况下,顺便说一句。我们在 JAX-RS 上进行自动上传,并且硬限制为 1 个文件,因此我不必处理超过 1 个项目。请注意,在重用此代码时,可能需要进行一些调整。

如您所见,这就是我正在做的所有事情,仅此而已。其余的只是默认实现,因为就我而言,我不关心任何一个。

一个小提示:不要关闭作者。冲一下就好了。关闭它将在写入响应之前关闭它。

于 2012-07-21T10:30:54.700 回答
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>
于 2012-07-19T07:31:24.503 回答
0

在这个后期阶段这可能没有用,但我最近有这个确切的要求,这是一个很容易解决的问题。假设您正在返回一个八位字节流,但如果出现问题,您只想返回纯 JSON。

  1. 不要在你的 restful 方法的声明中指定 @Produces。
  2. 根据您的方法中发生的情况,您将要做这种事情

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

因此,例如,如果您需要使用 JSON 对象而不是八位字节流提前返回,那么只需执行

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

重要的是在构建响应时指明 MediaType。

希望这可以帮助某人。

于 2017-05-10T13:43:41.050 回答