2013-03-07 15 views
19

Ajax çağrılarını işleyen ve JSON'u döndüren bir denetleyici yöntemim var. JSON'u oluşturmak için json.org'dan JSON kütüphanesini kullanıyorum.Yay MVC 3.1 denetleyicisinin işleyici yönteminde yanıt çıkış akışına doğrudan aktar

aşağıdaki yapabileceğini:

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

    // Populate JSON 

    return rootJson.toString(); 
} 

Ama araya JSON dizesi koymak verimsiz, sadece Bahar yanıtın çıktı akışına yazmak zorunda.

Bunun yerine, böyle tepki çıkış akımına doğrudan yazabilirsiniz:

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

    // Populate JSON 

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

Ama işleyicisi içine HttpServletResponse geçen başvurmak zorunda kalmadan daha bunu yapmak için daha iyi bir yol olacak gibi görünüyor yöntem.

Kullanabileceğim işleyici yönteminden @ResponseBody ek açıklamasının yanı sıra döndürülebilen başka bir sınıf veya arabirim var mı?

+0

"işleyici yöntem haline HttpServletResponse geçen" nesi var? – arahant

+2

@arahant - Bu adil bir soru. Sanırım, her ne kadar mümkün olsa da, bir şeyler yapmanın doğru yolu değil. Bu soruda @Ralph'in bir yanıtı var (http://stackoverflow.com/questions/5673260/downloading-a-file-from-spring-controllers) testlerin zorlaştığını söylüyor. Bunu yapan çok sayıda işleyici yöntemi yazmadan önce, başka bir yol olup olmadığını öğrenmek istedim. Şimdiye kadar bir özel 'HttpMessageConverter' yazmak zorunda kalacakmış gibi görünüyor. –

cevap

29

Çıkış Akışı veya Yazıcınızı denetleyici yönteminizin bir parametresi olarak alabilirsiniz.

@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

Not; Bir parametre olarak OutputStream veya Writer kullanarak HttpServletResponse daha testlerde kullanmak hala çok daha kolay olduğunu hissediyorum - Sonunda what I have written ;-)

+0

Cevabınız için teşekkürler. 'HttpServletResponse' komutunu iletmek için' OutputStream' veya 'Writer' tercih edilmesi tercih edilir. –

3

dikkat ve teşekkür, bunun için bir HttpMessageConverter yazdı. Bununla beraber, ben aşağıdakileri yapabilirsiniz:

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

    // Populate JSON 

    return rootJson; 
} 

benim HttpMessageConverter sınıftır:

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 Bahar kayıtlı olması gerekir. Bu böyle dispatcher-servlet.xml dosyada yapılabilir: Gördüğünüz gibi

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

, başka HttpMessageConverter nesneler de kayıtlı olması. Sipariş önemli.

+0

En güncel mesaj olan güncel bir yanıtla kendi gönderilerinizi yanıtlamak için zaman ayırdığınız için teşekkür ederiz. –

+0

@SteveMARION - Rica ederim. Bunu yapmakla uğraşacak tek kişi benim gibi görünüyordu. Bu cevabın kabul edilen cevap kadar oy alamayacağını düşündüm, ama daha yakın olacağını düşündüm. –

1

Eğer OutputStream veya Yazıcısını kullanırsanız, başlıkları kendiniz yazmanız gerektiğini unutmayın.

Tek geçici çözüm InputStreamResource/ResourceHttpMessageConverter kullanmaktır

İlgili konular