2012-07-19 1 views
0

새 프로젝트의 경우 클라이언트 측에서 jQuery 구성 요소를 사용하며 그 중 하나는 blueImp 파일 업 로더입니다. 우리는 코드를 행복하게 작성했으며, 누군가가 Internet Explorer에서 사이트를 열려고 시도 할 때까지 Chrome 및 Firefox에서 모든 것이 잘 작동했습니다. 분명히 IE는이 업로드 구성 요소를 사용할 때 서버에서 응용 프로그램/json 반환을 처리 할 수 ​​없습니다. 또한 파일로 사용자에게 스트림을 보냅니다. 어쨌든 많은 사용자가이 문제 (사이트에서 언급 한 것입니다 : https://github.com/blueimp/jQuery-File-Upload/wiki/Frequently-Asked-Questions 및 버그보고 기 다른 곳)@ 조건을 기반으로 주석을 생성합니다.

그러나 여기에 언급 된 대부분의 해결 방법은 PHP를 기반으로합니다. JAX-RS는 JAX-RS와 같은 서버 측에서 Java를 사용하고 있습니다. 자, JAX-RS는이 멋진 @Produces 어노테이션을 가지고 있습니다. 이것은 매우 정교합니다. 나는 문서를 파고 있었지만 더 현명하지 못했습니다. 이 @Produces 주석에 조건을 추가 할 수있는 방법이 있습니까? 그것을 명확하게하려면 : 사용자가 IE를 사용할 때 text/plain (또는 이와 비슷한 것)을 반환하고 사용자가 브라우저를 사용할 때 application/json을 반환하려고합니다 ... eeeerrrm, 다른 브라우저 :-)

감사합니다.

+1

아마도 IE의 Accept 헤더를 변경 한 후 JAX-RS에서이를 전달할 수있는 서블릿 필터일까요? 또는 IE에서 JAX-RS의 출력을 가로 채고 재 작성하는 필터입니까? – Thilo

+0

또한 diff @produces를 사용하여 두 가지 방법을 사용할 수 있으며 동일한 방법으로 구분할 수 있습니다. –

+0

와우, 빠른 답장, 고맙습니다 .-) @Thilo : 필터의 응답을 정말로 다시 쓰고 싶지는 않지만, 이음새가 가능해야합니다. 그러나 그것은 고려해야 할 것으로 보입니다. 감사! – gjoris

답변

1

나는 eventuallly (내가 여기에 질문을하기 전에해야 할 시작한 일을 실제로) 내 자신의 공급자를 작성하여 문제를 해결했다. 관심 (아직 모르는) 사람들을 위해 : 필요한를 오버라이드 (override)의 MessageBodyWriter 인터페이스를 구현하는 클래스에 @provider 추가

  • 다음 @Produces()
  • : 자신의 공급자를 작성하는 2 단계를 포함
    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이며 getter와 setter를 사용하여 url, size 및 name 필드가 있습니다.

text/plain을 반환하면 blueImp jQuery Fileupload가 작동한다는 것을 알 수 있습니다. 따라서이 텍스트는 UploadResponse의 텍스트/일반 출력용 제공자입니다.

여기서 내가하는 일은 JSON 개체를 만들고 목록에 넣은 다음 해당 목록을 응답에 쓰는 것입니다. 내 UI가 기대하기 때문에 나는 UploadResponses의 목록을 만들고있다. blueImp 파일 업로드에서는 기본적으로 btw가 필요합니다. JAX-RS의 자동 업로드와 1 개의 파일에 대한 하드 제한을 수행 중이므로 하나 이상의 항목을 처리 할 필요가 없습니다. 이 코드를 재사용 할 때 약간의 수정이 필요할 수 있습니다.

여러분도 알다시피, 그게 전부입니다. 나머지는 단지 기본 구현입니다. 왜냐하면 제 경우에는 그 중 아무 것도 신경 쓰지 않기 때문입니다.

작은 메모 : 작성자를 닫지 마십시오. 그냥 내버려둬. 그것을 닫으면 응답에 쓰기 전에 닫힙니다.

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> 
+0

응답이 이미 커밋 된 경우 더 이상 Content-Type 헤더를 변경할 수 없습니다. – Thilo

+0

좋은 지적. 그것은 항상 나를 잡습니다. 어쩌면 일부 aspectj aop은 비슷한 것을하기 위해 사용될 수 있지만 응답이 커밋되기 전에 사용됩니다. – theon

+0

실제로 Thilo가 옳습니다. 필터링을 사용하여 주변을 둘러 보려고했으나, 이미 말한 것처럼 응답이 이미 커밋 되었기 때문에 제대로 작동하지 않았습니다. – gjoris

0

이것은 늦은 단계에서는 쓸모가 없을 수도 있지만 최근이 정확한 요구 사항이 있었으며 매우 쉽게 수정되었습니다.옥텟 스트림을 반환한다고 가정 해 보겠습니다.하지만 문제가 발생하면 일반 JSON 만 반환하고 싶습니다.

  1. 편안한 방법을 선언 할 때 @Produces를 지정하지 마십시오. 예를 들어 당신이 octet- 대신 JSON 객체와 조기 반환에 필요한 경우,

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

그래서 이런 종류의 일을하려고하는 당신의 방법에 무슨 일을 바탕으로

  • 스트림을 입력 한 다음 수행하십시오.

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

    중요한 것은 응답을 빌드 할 때 MediaType을 지정하는 것입니다.

    희망이 있으면 도움이됩니다.