2013-03-07 12 views
19

私はajax呼び出しを処理し、JSONを返すコントローラメソッドを持っています。私はjson.orgのJSONライブラリを使用してJSONを作成しています。Spring MVC 3.1コントローラのハンドラメソッドで応答出力ストリームに直接ストリーム

私は、次の操作を行うことができます:

@RequestMapping(method = RequestMethod.POST) 
@ResponseBody 
public String getJson() 
{ 
    JSONObject rootJson = new JSONObject(); 

    // Populate JSON 

    return rootJson.toString(); 
} 

しかし、唯一の春には、応答の出力ストリームに書き込み持つように、JSON文字列を一緒に置くことは非効率的です。

代わりに、私はこのような応答出力ストリームに直接書き込むことができます。

@RequestMapping(method = RequestMethod.POST) 
public void getJson(HttpServletResponse response) 
{ 
    JSONObject rootJson = new JSONObject(); 

    // Populate JSON 

    rootJson.write(response.getWriter()); 
} 

しかしハンドラにHttpServletResponseを渡すに頼らよりも、これを行うには良い方法があるだろうように思えます方法。

@ResponseBodyアノテーションとともに使用できるハンドラメソッドから返される別のクラスまたはインタフェースがありますか?

+0

InputStreamResource/ResourceHttpMessageConverterを使用することですか? – arahant

+2

@arahant - これは公正な質問です。私はそれが可能ではあるが、正しいことをする方法ではないという印象を受けていると思う。 @Ralphの[この質問](http://stackoverflow.com/questions/5673260/downloading-a-file-from-spring-controllers)には、テストを難しくしているという回答があります。これを行うハンドラメソッドをたくさん書く前に、別の方法があるかどうかを知りたいと思っていました。これまでのところ、カスタムの 'HttpMessageConverter'を書く必要があるようです。 –

答えて

29

コントローラメソッドのパラメータとしてOutput StreamまたはWriterを使用できます。

@RequestMapping(method = RequestMethod.POST) 
public void getJson(Writer responseWriter) { 
    JSONObject rootJson = new JSONObject(); 
    rootJson.write(responseWriter); 
} 

@see Spring Reference Documentation 3.1 Chapter 16.3.3.1 Supported method argument types

P.S.私は、パラメータとしてOutputStreamまたはWriterを使用すると、まだHttpServletResponseよりもテストで使用するはるかに簡単であることを感じて - そして最後にwhat I have written ;-)

+0

答えをありがとう。 'OutputStream'または' Writer'を渡すことは 'HttpServletResponse'を渡す方が望ましいです。 –

3

に注意を払うためのおかげで、私はこのためHttpMessageConverterを書きました。これで、私は次の操作を実行できます。

@RequestMapping(method = RequestMethod.POST) 
@ResponseBody 
public JSONObject getJson() 
    throws JSONException 
{ 
    JSONObject rootJson = new JSONObject(); 

    // Populate JSON 

    return rootJson; 
} 

ここに私のHttpMessageConverterクラスです:

package com.example; 

import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.nio.charset.Charset; 
import org.json.JSONException; 
import org.json.JSONObject; 
import org.springframework.http.HttpInputMessage; 
import org.springframework.http.HttpMessage; 
import org.springframework.http.HttpOutputMessage; 
import org.springframework.http.MediaType; 
import org.springframework.http.converter.AbstractHttpMessageConverter; 
import org.springframework.http.converter.HttpMessageNotReadableException; 
import org.springframework.http.converter.HttpMessageNotWritableException; 

public class JsonObjectHttpMessageConverter 
    extends AbstractHttpMessageConverter<JSONObject> 
{ 
    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); 

    public JsonObjectHttpMessageConverter() 
    { 
     super(new MediaType("application", "json"), new MediaType("text", "javascript")); 
    } 

    @Override 
    protected boolean supports(Class<?> clazz) 
    { 
     return JSONObject.class.equals(clazz); 
    } 

    @Override 
    protected JSONObject readInternal(Class<? extends JSONObject> clazz, 
             HttpInputMessage   inputMessage) 
     throws IOException, 
       HttpMessageNotReadableException 
    { 
     throw new UnsupportedOperationException(); 
    } 

    @Override 
    protected void writeInternal(JSONObject  jsonObject, 
           HttpOutputMessage outputMessage) 
     throws IOException, 
       HttpMessageNotWritableException 
    { 
     PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputMessage.getBody(), 
                    getContentTypeCharset(outputMessage))); 

     try 
     { 
      jsonObject.write(writer); 
      writer.flush(); 
     } 
     catch (JSONException e) 
     { 
      throw new HttpMessageNotWritableException(e.getMessage(), e); 
     } 
    } 

    private Charset getContentTypeCharset(HttpMessage message) 
    { 
     MediaType contentType = message.getHeaders().getContentType(); 

     Charset charset = (contentType != null) ? contentType.getCharSet() : null; 

     return (charset != null) ? charset : DEFAULT_CHARSET; 
    } 
} 

HttpMessageConverterは春に登録する必要があります。あなたが見ることができるように、私も登録されている他のHttpMessageConverterオブジェクトを持って

<beans ...> 

    ...  

    <mvc:annotation-driven conversion-service="conversionService" validator="validator"> 
     <mvc:argument-resolvers> 
      ... 
     </mvc:argument-resolvers> 
     <mvc:message-converters> 
      <bean class="org.springframework.http.converter.StringHttpMessageConverter"> 
       <property name="supportedMediaTypes"> 
        <list> 
         <value>text/plain;charset=UTF-8</value> 
         <value>application/json;charset=UTF-8</value> 
         <value>*/*</value> 
        </list> 
       </property> 
       <property name="writeAcceptCharset" value="false" /> 
      </bean> 
      <bean class="com.example.JsonObjectHttpMessageConverter" /> 
      <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> 
       <property name="objectMapper" ref="jacksonObjectMapper" /> 
      </bean> 
     </mvc:message-converters> 
    </mvc:annotation-driven> 

    ... 

</beans> 

:これは、このようなdispatcher-servlet.xmlファイルで行うことができます。順序は重要です。

+0

更新した回答で自分の投稿に返信していただきありがとうございます。これはIMHOのベストです。 –

+0

@SteveMARION - ようこそ。これをやることを邪魔する唯一の人だったように見えました。私はこの答えが受け入れられた答えと同じくらい多くの票を得ることはできないと考えましたが、それはもっと近いと思っていました。 –

1

OutputStreamまたはWriterを使用する場合は、ヘッダーを自分で書き込む必要があります。

回避策の一つは、「ハンドラメソッドへのHttpServletResponseを渡す」と間違っている何

関連する問題