![](/img/trans.png)
[英]Jackson JSON Streaming API: Read an entire object directly to String
[英]Streaming JSON directly to response with Jackson
當前,我需要向ajax請求發送一個大型json對象。 為此,我使用了下面的工作正常的控制器方法。
@RequestMapping(method = RequestMethod.POST,params = {"dynamicScenario"})
@ResponseBody
public String getDynamicScenarioData(@RequestParam Map<String, String> map) throws JsonParseException, JsonMappingException, IOException
{
ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("unchecked")
Map<String,Object> queryParameters = mapper.readValue(map.get("parameters") , Map.class);
Map<String, Object> getData = service.runDynamicScenario(queryParameters, map.get("queryString"));
return writer.writeValueAsString(getData); //here java throws java.lang.OutOfMemoryError: Java heap space memory
}
更新:我的ajax是:
$.ajax({
type: "POST",
url: "dynamicScenario.htm",
data : tags,
dataType: "json",
success: function(data){});
我的DispatcherServlet設置:
public class ApplicationInitializer implements WebApplicationInitializer
{
public void onStartup(ServletContext servletContext) throws
ServletException
{
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(ApplicationConfig.class);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic servletRegistration = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
servletRegistration.setLoadOnStartup(1);
servletRegistration.addMapping("*.htmlx");
}
}
我正在使用傑克遜序列化不同對象的地圖,然后將其發送回ajax。 但是,如果json的大小很大,則Java會拋出內存不足。 我知道Jackson方法writer.writeValueAsString效率低下,因為它寫入字符串,但是還有其他選擇嗎? 我不能使用普通的Java POJO,因為我不知道要序列化的映射將包含哪些對象,因此我不能簡單地將其映射到某些Java對象。 有任何想法嗎? 謝謝
您要解決的問題是
return writer.writeValueAsString(getData);
創建太大的String
並導致OutOfMemoryError
。 Jackson支持Streaming API ,Spring在其MappingJackson2HttpMessageConverter
使用了該API ,該API在響應正文(和請求正文)中處理將POJO序列化為JSON。
有幾種方法可以解決此問題。 最簡單的方法是將返回類型更改為Map<String, Object
並直接返回相應的對象。
@RequestMapping(method = RequestMethod.POST,params = {"dynamicScenario"})
@ResponseBody
public Map<String, Object> getDynamicScenarioData(@RequestParam Map<String, String> map) throws JsonParseException, JsonMappingException, IOException
{
ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("unchecked")
Map<String,Object> queryParameters = mapper.readValue(map.get("parameters") , Map.class);
Map<String, Object> getData = service.runDynamicScenario(queryParameters, map.get("queryString"));
return getData;
}
Spring將通過將結果直接流式傳輸到響應OutputStream
來對getData
進行序列化。
這將無法單獨工作。 例如,您用來訪問服務的網址
/dynamicScenario.htm
導致Spring的內容協商開始。它看到.htm
並認為您期望text/html
內容。 關閉內容協商或使用不帶擴展名的URL
/dynamicScenario
然后,Spring將查看Accept
標頭,以弄清客戶的期望。 因為那是
dataType: "json"
它將使用MappingJackson2HttpMessageConverter
編寫application/json
。
這里還有一些要解決的問題
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(ApplicationConfig.class);
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic servletRegistration = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
servletRegistration.setLoadOnStartup(1);
servletRegistration.addMapping("*.htmlx");
當前,您正在使ContextLoaderListener
和DispatcherServlet
加載相同的ApplicationContext
。 這是不必要的,並且可能有害。 DispatcherServlet
已經使用ContextLoaderListener
上下文作為父上下文。 你可以在這里讀更多關於它的內容:
如果您的ApplicationConfig
僅包含MVC配置元素,則僅讓DispatcherServlet
加載它。 您將不需要ContextLoaderListener
。
如果它具有與MVC堆棧無關的其他類型的配置元素,請將其拆分為兩個@Configuration
類。 將MVC一個傳遞給DispatcherServlet
,另一個傳遞給ContextLoaderListener
。
不要將JSON作為表單參數傳遞。 將其直接傳遞到請求正文中,並使用@RequestBody
直接將其反序列化為所需的類型。
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> getDynamicScenarioData(@RequestBody Map<String,Object> queryParameters) throws JsonParseException, JsonMappingException, IOException
{
Map<String, Object> getData = service.runDynamicScenario(queryParameters, /* find a better way to pass this map.get("queryString") */);
return getData;
}
您可以為每個請求保存一個ObjectMapper
對象(這是一個繁重的對象),並讓Spring負責所有反序列化(再次進行流式處理)。 您將必須找到另一種傳遞queryString
(您仍然可以將其作為單個查詢參數傳遞,並通過`@RequestParam獲取)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.