2011-02-16 8 views
30

मुझे जैक्सन पसंद नहीं है।कस्टम HttpMessageConverter @ResponseBody के साथ जेसन चीजें करने के लिए

मैं AJAX का उपयोग करना चाहता हूं लेकिन Google Gson के साथ।

तो मैं अपने खुद के HttpMessageConverter को @ResponseBody एनोटेशन के साथ उपयोग करने के तरीके को समझने का प्रयास कर रहा हूं। क्या कोई मुझे रास्ता दिखाने के लिए समय ले सकता है जिस तरह मुझे जाना चाहिए? मुझे किस कॉन्फ़िगरेशन चालू करना चाहिए? मैं भी सोच रहा हूं कि क्या मैं ऐसा कर सकता हूं और अभी भी < एमवीसी का उपयोग कर सकता हूं: एनोटेशन-संचालित/>?

अग्रिम धन्यवाद।

मैंने इसे पहले ही स्प्रिंग कम्युनिटी फोर्न्स में बिना किसी जवाब के पूछा है, इसलिए मैं यह देखने के लिए यहां पूछ रहा हूं कि मुझे बेहतर मौका मिलता है या नहीं। Spring Community Forums link to my question

मैं भी वेब पर एक संपूर्ण खोज कर दिया है और इस विषय पर कुछ दिलचस्प पाया लेकिन यह वे वसंत 3.1 में यह डाल करने के लिए सोच रहे हैं और मैं अभी भी वसंत 3.0.5 का उपयोग कर रहा लगता है: Jira's Spring Improvement ask

खैर ... अब मैं अपने आप को पता लगाने के लिए यह करने के लिए डिबग स्प्रिंग कोड की कोशिश कर रहा हूँ, लेकिन मैं कुछ समस्या आ रही है की तरह मैं यहाँ कहा है: अगर एक और है Spring Framework Build Error

ऐसा करने का तरीका और मैं इसे याद कर रहा हूं, कृपया मुझे बताएं।

उत्तर

35

... यह जवाब खोजने के लिए इतनी मेहनत था और मैं तो पालन किया था: के बाद से 3.1 वर्तमान में केवल एक मील का पत्थर रिहाई (एम 1) है, मैं इसे बनाने के बाद अपने कनवर्टर इस तरह से दर्ज की सुझाव देंगे अपूर्ण जानकारी के लिए कई संकेत जो मुझे लगता है कि यहां पूरा जवाब पोस्ट करना अच्छा होगा। तो अगले के लिए यह खोजना आसान होगा।

 

package net.iogui.web.spring.converter; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.Reader; 
import java.io.StringWriter; 
import java.io.Writer; 
import java.nio.charset.Charset; 

import org.springframework.http.HttpInputMessage; 
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; 

import com.google.gson.Gson; 
import com.google.gson.JsonSyntaxException; 

public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Object> { 

    private Gson gson = new Gson(); 

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); 

    public GsonHttpMessageConverter(){ 
     super(new MediaType("application", "json", DEFAULT_CHARSET)); 
    } 

    @Override 
    protected Object readInternal(Class<? extends Object> clazz, 
            HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { 

     try{ 
      return gson.fromJson(convertStreamToString(inputMessage.getBody()), clazz); 
     }catch(JsonSyntaxException e){ 
      throw new HttpMessageNotReadableException("Could not read JSON: " + e.getMessage(), e); 
     } 

    } 

    @Override 
    protected boolean supports(Class<?> clazz) { 
     return true; 
    } 

    @Override 
    protected void writeInternal(Object t, 
           HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { 

     //TODO: adapt this to be able to receive a list of json objects too 

     String json = gson.toJson(t); 

     outputMessage.getBody().write(json.getBytes()); 
    } 

    //TODO: move this to a more appropriated utils class 
    public String convertStreamToString(InputStream is) throws IOException { 
     /* 
     * To convert the InputStream to String we use the Reader.read(char[] 
     * buffer) method. We iterate until the Reader return -1 which means 
     * there's no more data to read. We use the StringWriter class to 
     * produce the string. 
     */ 
     if (is != null) { 
      Writer writer = new StringWriter(); 

      char[] buffer = new char[1024]; 
      try { 
       Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 
       int n; 
       while ((n = reader.read(buffer)) != -1) { 
        writer.write(buffer, 0, n); 
       } 
      } finally { 
       is.close(); 
      } 
      return writer.toString(); 
     } else { 
      return ""; 
     } 
    } 

} 
 

तब मैं annnotaion संचालित टैग पर पट्टी और वसंत-MVC विन्यास फाइल पर अपने ही हाथों से सभी को कॉन्फ़िगर करने के लिए किया था:

 

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 

    <!-- Configures the @Controller programming model --> 

    <!-- To use just with a JSR-303 provider in the classpath 
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> 
    --> 

    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" /> 

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
     <property name="webBindingInitializer"> 
      <bean class="net.iogui.web.spring.util.CommonWebBindingInitializer" /> 
     </property> 
     <property name="messageConverters"> 
      <list> 
       <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /> 
       <bean class="org.springframework.http.converter.StringHttpMessageConverter" /> 
       <bean class="org.springframework.http.converter.ResourceHttpMessageConverter" /> 
       <bean class="net.iogui.web.spring.converter.GsonHttpMessageConverter" /> 
       <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" /> 
       <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" /> 
       <!-- bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /--> 
      </list> 
     </property> 
    </bean> 
    <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> 


    <context:component-scan base-package="net.iogui.teste.web.controller"/> 

    <!-- Forwards requests to the "/" resource to the "login" view --> 
    <mvc:view-controller path="/" view-name="home"/> 

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory --> 
    <mvc:resources mapping="/resources/**" location="/resources/" /> 

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> 
     <property name="prefix" value="/WEB-INF/view/"/> 
     <property name="suffix" value=".jsp"/> 
    </bean> 

</beans> 
 

सबसे पहले मैं कस्टम HttpMessageConverter को लागू करने के लिए किया था

कि, Formater और सत्यापनकर्ता काम करने के लिए बनाने के लिए देखें, हम एक कस्टम बनाने की कोई आवश्यकता webBindingInitializer भी:

 

package net.iogui.web.spring.util; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.core.convert.ConversionService; 
import org.springframework.validation.Validator; 
import org.springframework.web.bind.WebDataBinder; 
import org.springframework.web.bind.support.WebBindingInitializer; 
import org.springframework.web.context.request.WebRequest; 

public class CommonWebBindingInitializer implements WebBindingInitializer { 

    @Autowired(required=false) 
    private Validator validator; 

    @Autowired 
    private ConversionService conversionService; 

    @Override 
    public void initBinder(WebDataBinder binder, WebRequest request) { 
     binder.setValidator(validator); 
     binder.setConversionService(conversionService); 
    } 

} 
 

एक दिलचस्प बात यह देखने के लिए आदेश annotaion चालित टैग के बिना विन्यास काम करने के लिए, हम स्वयं एक AnnotationMethodHandlerAdapter और एक DefaultAnnotationHandlerMapping कॉन्फ़िगर करने के लिए होता है।और व्यवस्था AnnotationMethodHandlerAdapter स्वरूपण और मान्यता से निपटने में सक्षम बनाने के लिए में, हम एक सत्यापनकर्ता, एक conversionService कॉन्फ़िगर करने के लिए और एक कस्टम webBindingInitializer का निर्माण करने के लिए किया था।

मुझे आशा है कि यह सब मेरे अलावा किसी और की मदद करेगा।

मेरी बेताब खोज पर, this @ बोझो पोस्ट बेहद उपयोग था। मैं @GaryF couse का भी आभारी हूं कि उसका जवाब मुझे @Bozho post पर ले गया। आप जो स्प्रिंग 3.1 में ऐसा करने की कोशिश कर रहे हैं, आप @ रॉबी तालाब जवाब देखें .. बहुत आसान है, है ना?

+0

धन्यवाद, मैं मैं जैक्सन के साथ ठीक हूँ, हालांकि मैं सोच रहा था कि मैं जीसन के साथ ऐसा कैसे करूंगा। बीटीडब्ल्यू, आप इनपुटस्ट्रीम से स्ट्रिंग प्राप्त करने के लिए अपाचे कॉमन्स IOUtils का उपयोग कर सकते थे। मैं आमतौर पर जहां संभव हो वहां तीसरे पक्ष के पुस्तकालयों का उपयोग करना पसंद करता हूं क्योंकि एक तेज़/बेहतर विकल्प आने पर मुझे कोड को बेहतर बनाने की आवश्यकता नहीं होती है, मैं बस मैवेन में संस्करण बदलता हूं :)। – Stef

+0

यह देखते हुए कि 'AnnotationMethodHandlerAdapter' अब बहिष्कृत है, क्या यह वही कॉन्फ़िगरेशन' RequestMappingHandlerAdapter' के साथ काम करता है? – Stewart

16

आपको एक GsonMessageConverter बनाना है जो AbstractHttpMessageConverter बढ़ाता है और अपने संदेश कनवर्टर को पंजीकृत करने के लिए एम vc-message-converters टैग का उपयोग करता है। वह टैग जैक्सन पर आपके कनवर्टर को प्राथमिकता देगा।

+0

ध्यान दें कि मैं निर्दिष्ट किया है: "मैं भी वेब पर एक exaustive खोज कर दिया है और इस विषय पर कुछ दिलचस्प पाया लेकिन यह वे वसंत 3.1 में यह डाल करने के लिए सोच रहे हैं लगता है और मैं अभी भी कर रहा हूँ वसंत 3.0.5 का उपयोग कर। " जिरा के सुधार अनुरोध – Iogui

+0

पर लिंक देखें ... उदाहरण के साथ एक जवाब अच्छा होगा। – 4gus71n

3

रॉबी तालाब मूल रूप से सही है, लेकिन ध्यान दें कि एमवीसी का उपयोग करने के उनके सुझाव: संदेश-कन्वर्टर्स टैग की आवश्यकता है कि आप 3.1 का उपयोग करें। खैर

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="messageConverters"> 
     <util:list id="beanList"> 
     <ref bean="someMessageConverter"/> 
     <ref bean="someOtherMessageConverter"/> 
     </util:list> 
    </property> 
</bean> 
+0

ठीक है, और मैं अभी भी टैग का उपयोग कर सकता हूं? इन टैग द्वारा पंजीकृत सभी एडाप्टर स्वचालित रूप से पंजीकृत होंगे? या मुझे एनोटेशन-संचालित टैग को बंद करना होगा और अपने कॉन्फ़िगरेशन को अपने हाथों से करना होगा? – Iogui

+0

आप सही हैं, समाधान मैन्युअल रूप से AnnotationMethodHandlerAdapter सेट करना है और यह संदेश कन्वर्टर्स है लेकिन इसका मतलब है कि मैं एनोटियन-संचालित का उपयोग नहीं कर सकता और मुझे मैन्युअल रूप से सभी सेटअप करना होगा। यह इतना अलग था और मुझे अपने objetive में पाने के लिए इतना समय लगा कि मैं इसे सब यहाँ पोस्ट करूंगा ताकि अगर कोई और इसके लिए खोज कर रहा है, तो यह वास्तव में उपयोगी जवाब होगा। – Iogui

+0

@logui Glad आपने बाकी को समझ लिया।ऐसा लगता है कि यह वसंत 3.1 में कम दर्दनाक होगा: http://blog.springsource.com/2011/02/21/spring-3-1-m1-mvc-namespace-enhancements-and-configuration/ – GaryF

3

या के रूप में Jira's Spring Improvement ask में उल्लेख किया है, एक BeanPostProcessor कि कहते हैं आपके HttpMessageConvertorAnnotationMethodHandlerAdapter

5

को मैं स्थिति है जहाँ जैक्सन के उपयोग की आवश्यकता होगी मुझे अन्य समूह की (एक ही कंपनी में) कोड को बदलना पड़ा लिखें। वह पसंद नहीं आया। इसलिए मैंने जीसन का उपयोग करना और टाइपएडएप्टर को आवश्यकतानुसार पंजीकृत करना चुना।

एक कनवर्टर को हुक किया और वसंत-परीक्षण (वसंत-एमवीसी-टेस्ट होने के लिए उपयोग किया जाता था) का उपयोग करके कुछ एकीकरण परीक्षण लिखे। इससे कोई फर्क नहीं पड़ता कि मैंने किस बदलाव की कोशिश की (एमवीसी का उपयोग: एनोटेशन-संचालित या बीन की मैन्युअल परिभाषा)। उनमें से कोई भी काम नहीं किया। इनमें से किसी भी संयोजन ने हमेशा जैक्सन कनवर्टर का उपयोग किया जो असफल रहा।

उत्तर> यह बताता है कि MockMvcBuilders की स्टैंडअलोनसेटअप विधि "हार्ड" ने संदेश कन्वर्टर्स को डिफ़ॉल्ट संस्करणों में कोड किया और उपरोक्त मेरे सभी परिवर्तनों को अनदेखा कर दिया।

@Autowired 
private RequestMappingHandlerAdapter adapter; 

public void someOperation() { 
    StandaloneMockMvcBuilder smmb = MockMvcBuilders.standaloneSetup(controllerToTest); 
    List<HttpMessageConverter<?>> converters = adapter.getMessageConverters(); 
    HttpMessageConverter<?> ary[] = new HttpMessageConverter[converters.size()]; 
    smmb.setMessageConverters(conveters.toArray(ary)); 
    mockMvc = smmb.build(); 
    . 
    . 
} 

आशा इस कोई मदद करता है, अंत में मैं इस्तेमाल एनोटेशन चालित और पुनः उद्देश्य तय एंड्रॉयड के कनवर्टर

3

आप यहाँ एक्सएमएल के साथ खिलवाड़ के बिना संदेश कनवर्टर जोड़ना चाहते हैं एक है: यहाँ क्या काम किया है सरल उदाहरण

@Autowired 
private RequestMappingHandlerAdapter adapter; 

@PostConstruct 
public void initStuff() { 
    List<HttpMessageConverter<?>> messageConverters = adapter.getMessageConverters(); 
    BufferedImageHttpMessageConverter imageConverter = new BufferedImageHttpMessageConverter();; 
    messageConverters.add(0,imageConverter); 
} 
0

आप WebConfig fil लिख कर ऐसा कर सकते हैं एक जावा फ़ाइल के रूप में ई। WebMvcConfigurerAdapter के साथ अपनी कॉन्फ़िगरेशन फ़ाइल बढ़ाएं और अपना इरादा संदेश कनवर्टर जोड़ने के लिए विस्तार मैसेज कन्वर्टर्स विधि ओवरराइड करें। यह विधि वसंत द्वारा जोड़े गए डिफ़ॉल्ट कन्वर्टर्स को बनाए रखेगी और अंत में आपके कनवर्टर को जोड़ देगा। स्पष्ट रूप से आप सूची के साथ पूर्ण नियंत्रण रखते हैं और आप सूची में जहां भी चाहें जोड़ सकते हैं।

@Configuration 
@EnableWebMvc 
@ComponentScan(basePackageClasses={WebConfig.class}) 
public class WebConfig extends WebMvcConfigurerAdapter { 
    @Override 
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { 
     converters.add(new GsonHttpMessageConverter()); 
    } 
} 

package net.iogui.web.spring.converter; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.Reader; 
import java.io.StringWriter; 
import java.io.Writer; 
import java.nio.charset.Charset; 

import org.springframework.http.HttpInputMessage; 
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; 

import com.google.gson.Gson; 
import com.google.gson.JsonSyntaxException; 

public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Object> { 

private Gson gson = new Gson(); 

public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); 

public GsonHttpMessageConverter(){ 
    super(new MediaType("application", "json", DEFAULT_CHARSET)); 
} 

@Override 
protected Object readInternal(Class<? extends Object> clazz, 
           HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { 

    try{ 
     return gson.fromJson(convertStreamToString(inputMessage.getBody()), clazz); 
    }catch(JsonSyntaxException e){ 
     throw new HttpMessageNotReadableException("Could not read JSON: " + e.getMessage(), e); 
    } 

} 

@Override 
protected boolean supports(Class<?> clazz) { 
    return true; 
} 

@Override 
protected void writeInternal(Object t, 
          HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { 

    //TODO: adapt this to be able to receive a list of json objects too 

    String json = gson.toJson(t); 

    outputMessage.getBody().write(json.getBytes()); 
} 

//TODO: move this to a more appropriated utils class 
public String convertStreamToString(InputStream is) throws IOException { 
    /* 
    * To convert the InputStream to String we use the Reader.read(char[] 
    * buffer) method. We iterate until the Reader return -1 which means 
    * there's no more data to read. We use the StringWriter class to 
    * produce the string. 
    */ 
    if (is != null) { 
     Writer writer = new StringWriter(); 

     char[] buffer = new char[1024]; 
     try { 
      Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 
      int n; 
      while ((n = reader.read(buffer)) != -1) { 
       writer.write(buffer, 0, n); 
      } 
     } finally { 
      is.close(); 
     } 
     return writer.toString(); 
    } else { 
     return ""; 
    } 
} 
संबंधित मुद्दे