我最近从使用Jersey切换到CXF以获得JAX-RS应用程序。我还使用StreamingOutput输出我自己的流,因为流中包含的数据需要大约20秒来创建,并且可以由客户端部分处理。这一切都适用于Jersey,但我现在已经切换到使用CXF返回JAXB bean并且无法获得流式传输行为。使用Jersey时,我必须将jersey.config.contentLength.buffer.server
设置为0
并刷新OutputStream
以将数据提供给客户端,但我无法找到与CXF等效的数据。我已尝试根据Interceptor
示例编写StreamInterceptor
,但write
的{{1}}的{{1}}方法直到所有人都被调用处理完成了。 JAXB bean包含一个Message
,其自定义OutputStream
可在数据可用时提供。我可以在调试器中看到数据缓冲。
如何使用CXF流式传输JAXB bean?
答案 0 :(得分:3)
我设法用Jackson和我自己的MessageBodyWriter,BeanSerializerModifier和JsonSerializer来做。我仍然需要找到一种使用XML的方法。
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
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.lang.annotation.Annotation;
import java.lang.reflect.Type;
/**
* Created by jayen on 17/12/13.
*/
@SuppressWarnings({"DefaultFileTemplate"})
@Produces({"application/json", "application/*+json"})
@Provider
public class ResponseJSONWriter implements MessageBodyWriter<Response> {
@Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return Response.class.isAssignableFrom(type);
}
@Override
public long getSize(Response response, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return -1;
}
@Override
public void writeTo(Response response, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
try {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JaxbAnnotationModule());
mapper.setSerializerFactory(
mapper.getSerializerFactory().withSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return new FlushingSerializer<>(serializer);
}
}));
mapper.writeValue(entityStream, response);
} catch (Throwable e) {
e.printStackTrace();
}
}
private class FlushingSerializer<T> extends JsonSerializer<T> {
private final JsonSerializer<T> serializer;
public FlushingSerializer(JsonSerializer<T> serializer) {
this.serializer = serializer;
}
@Override public void serialize(T value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
serializer.serialize(value, jgen, provider);
jgen.flush();
}
}
}