0

新しいプロジェクトでは、クライアント側でjQueryコンポーネントを使用しています。その1つがblueImpファイルアップローダーです。私たちはコードを楽しく書いていましたが、ChromeとFirefoxではすべてがうまく機能しました...誰かがInternetExplorerでサイトを開こうとするまでは。どうやら、このアップロードコンポーネントを使用する場合、IEはサーバーからのapplication / jsonリターンを処理できません。さらに、IEはそれをファイルとしてユーザーにストリーミングするだけです。とにかく、多くのユーザーがこの問題を抱えています(これは彼らのサイトで言及されています: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

私は最終的に自分のプロバイダーを作成することで問題を解決しました(これは実際、ここで質問する前に始めたものです)。興味のある人(そしてまだ知らない人)のために:あなた自身のプロバイダーを書くことは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、size、nameがあり、getterとsetterがあります。

text / plainを返すと、blueImp jQuery Fileuploadが機能するようになることを読みました。したがって、これは、UploadResponseのtext/plain出力のプロバイダーです。

ここで行うのは、JSONオブジェクトを作成し、それをリストに入れて、そのリストを応答に書き込むことです。私のUIはそれを期待しているので、UploadResponsesのリストを作成しています。blueImp File Uploadは、デフォルトでそれを想定しています。JAX-RSで自動アップロードを行っており、1つのファイルにハード制限しているため、複数のアイテムを処理する必要はありません。このコードを再利用するときは、いくつかの調整が必要になる場合があることに注意してください。

ご覧のとおり、私がしているのはそれだけです。私の場合、私はそれを気にしないので、残りは単なるデフォルトの実装です。

小さなメモ:ライターを閉じないでください。フラッシュするだけです。閉じると、応答に書き込む前に閉じます。

于 2012-07-21T10:30:54.700 に答える
0

サーブレットフィルタの使用は機能するはずです。これが(テストされていない)ものです:

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 に答える