स्प्रिंग MVC (@ResponseBody) में प्रतिक्रिया सामग्री-प्रकार कौन सेट करता है


126

मैं अपने एनोटेशन द्वारा संचालित स्प्रिंग एमवीसी जावा वेब एप्लिकेशन को जेटी वेब सर्वर (वर्तमान में मैवेन जेट्टी प्लगइन) में चला रहा हूं।

मैं एक नियंत्रक विधि के साथ कुछ AJAX समर्थन करने की कोशिश कर रहा हूं बस स्ट्रिंग सहायता पाठ वापस कर रहा हूं। संसाधन UTF-8 एन्कोडिंग में हैं और इसलिए स्ट्रिंग है, लेकिन सर्वर से मेरी प्रतिक्रिया आती है

content-encoding: text/plain;charset=ISO-8859-1 

यहां तक ​​कि जब मेरा ब्राउज़र भेजता है

Accept-Charset  windows-1250,utf-8;q=0.7,*;q=0.7

मैं वसंत के किसी भी तरह डिफ़ॉल्ट विन्यास का उपयोग कर रहा हूं

मुझे इस बीन को कॉन्फ़िगरेशन में जोड़ने के लिए एक संकेत मिला है, लेकिन मुझे लगता है कि यह अभी उपयोग नहीं किया गया है, क्योंकि यह कहता है कि यह एन्कोडिंग का समर्थन नहीं करता है और इसके बजाय एक डिफ़ॉल्ट का उपयोग किया जाता है।

<bean class="org.springframework.http.converter.StringHttpMessageConverter">
    <property name="supportedMediaTypes" value="text/plain;charset=UTF-8" />
</bean>

मेरा नियंत्रक कोड है (ध्यान दें कि प्रतिक्रिया प्रकार का यह परिवर्तन मेरे लिए काम नहीं कर रहा है):

@RequestMapping(value = "ajax/gethelp")
public @ResponseBody String handleGetHelp(Locale loc, String code, HttpServletResponse response) {
    log.debug("Getting help for code: " + code);
    response.setContentType("text/plain;charset=UTF-8");
    String help = messageSource.getMessage(code, null, loc);
    log.debug("Help is: " + help);
    return help;
}

जवाबों:


59

StringHttpMessageConverterबीन की सरल घोषणा पर्याप्त नहीं है, आपको इसे इंजेक्ट करने की आवश्यकता है AnnotationMethodHandlerAdapter:

<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <array>
            <bean class = "org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
            </bean>
        </array>
    </property>
</bean>

हालाँकि, इस विधि का उपयोग करके आपको सभी HttpMessageConverters को फिर से परिभाषित करना होगा , और इसके साथ काम नहीं करना चाहिए<mvc:annotation-driven />

तो, शायद सबसे सुविधाजनक लेकिन बदसूरत तरीका इसके AnnotationMethodHandlerAdapterसाथ तात्कालिकता को रोकना है BeanPostProcessor:

public class EncodingPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String name)
            throws BeansException {
        if (bean instanceof AnnotationMethodHandlerAdapter) {
            HttpMessageConverter<?>[] convs = ((AnnotationMethodHandlerAdapter) bean).getMessageConverters();
            for (HttpMessageConverter<?> conv: convs) {
                if (conv instanceof StringHttpMessageConverter) {
                    ((StringHttpMessageConverter) conv).setSupportedMediaTypes(
                        Arrays.asList(new MediaType("text", "html", 
                            Charset.forName("UTF-8"))));
                }
            }
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String name)
            throws BeansException {
        return bean;
    }
}

-

<bean class = "EncodingPostProcessor " />

10
यह एक गंदे हैक की तरह लगता है। मुझे यह पसंद नहीं है लेकिन उपयोग करने के लिए। स्प्रिंग फ्रेमवर्क डेवलपर्स को इस मामले पर काम करना चाहिए!
digz6666

लाइन <bean class = "EncodingPostProcessor" /> कहाँ जाती है?
राशि

1
@zod: DispatcherServlet's config ( ...-servlet.xml)
axtavt

धन्यवाद। यह नजरअंदाज किया जा रहा है। हम mvc (मुझे लगता है) का उपयोग कर रहे हैं और हमारे पास @Controller विशेषता वाला एक वर्ग है, जो प्रवेश बिंदु प्रतीत होता है। वर्ग का कहीं और उल्लेख नहीं किया गया है (इसका एक समान नाम वाला एक इंटरफ़ेस है) फिर भी इसे तत्काल और सही ढंग से कहा जाता है। पथों को @RequestMapping विशेषता के साथ मैप किया जाता है। हम प्रतिक्रिया के सामग्री प्रकार को नियंत्रित करने में असमर्थ हैं (हमें xml की आवश्यकता है)। जैसा कि आप शायद बता सकते हैं, मुझे नहीं पता कि मैं क्या कर रहा हूं, और इसे बनाने वाले डेवलपर ने मेरी कंपनी छोड़ दी है। धन्यवाद।
राशि

3
जैसा कि @ digz6666 का कहना है कि यह एक गंदा हैक है। वसंत को यह देखना चाहिए कि JAX-RS इसे कैसे करता है।
एडम जेंट

166

मुझे स्प्रिंग 3.1 का समाधान मिला। @ResponseBody एनोटेशन का उपयोग करने के साथ। यहाँ JSON आउटपुट का उपयोग करते हुए नियंत्रक का उदाहरण दिया गया है:

@RequestMapping(value = "/getDealers", method = RequestMethod.GET, 
produces = "application/json; charset=utf-8")
@ResponseBody
public String sendMobileData() {

}

7
+1। इसने इसे मेरे लिए भी हल कर दिया, लेकिन केवल तभी जब मैंने <mvc:annotation-driven/>applicationContext में उपयोग किया। (इसके बजाय <bean class=" [...] DefaultAnnotationHandlerMapping"/>, जो वैसे भी स्प्रिंग 3.2 में पदावनत है ...)
जोनिक

अगर यह इस तरह से एनोटेट किया जाता है तो यह एप्लिकेशन / xml का उत्पादन करता है?
हुरडा

2
@ हुरडा: जाहिर है आप किसी भी सामग्री प्रकार को निर्दिष्ट कर सकते हैं जिसे आप producesविशेषता के मूल्य को बदलकर चाहते हैं ।
जोनीक

1
"Application / json" के लिए एक MediaType.APPLICATION_JSON_VALUE भी है।
देव

2
UTF-8 के लिए, देखें MediaType.APPLICATION_JSON_UTF8_VALUE
कैल्विनफ

51

ध्यान दें कि स्प्रिंग MVC 3.1 में आप संदेश कन्वर्टर्स को कॉन्फ़िगर करने के लिए MVC नामस्थान का उपयोग कर सकते हैं:

<mvc:annotation-driven>
  <mvc:message-converters register-defaults="true">
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
      <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
    </bean>
  </mvc:message-converters>
</mvc:annotation-driven>

या कोड-आधारित कॉन्फ़िगरेशन:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

  private static final Charset UTF8 = Charset.forName("UTF-8");

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
    stringConverter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", UTF8)));
    converters.add(stringConverter);

    // Add other converters ...
  }
}

कार्यों के प्रकार, सिवाय इसके कि 1) यह एक Accept-Charsetहेडर के साथ प्रतिक्रिया को प्रदूषित करता है जो संभवतः हर ज्ञात वर्ण एन्कोडिंग को सूचीबद्ध करता है, और 2) जब अनुरोध में Acceptहेडर supportedMediaTypesहोता है तो कनवर्टर की संपत्ति का उपयोग नहीं किया जाता है , इसलिए उदाहरण के लिए जब मैं अनुरोध टाइप करता हूं एक ब्राउज़र में सीधे URL की प्रतिक्रिया के Content-Type: text/htmlबजाय एक हेडर है।
Giulio Piancastelli

3
आप "पाठ / सादे" के रूप में वैसे भी डिफ़ॉल्ट रूप से सरल कर सकते हैं: <bean class="org.springframework.http.converter.StringHttpMessageConverter"><constructor-arg value="UTF-8" /></bean>
इगोर मुखिन

इस उत्तर को सही उत्तर के रूप में स्वीकार किया जाना चाहिए। इसके अलावा, @IgorMukhin का तरीका StringHttpMessageConverter सेम कार्यों को परिभाषित करने का है। इस उत्तर का उपयोग सभी सर्वलेट्स के लिए प्रतिक्रिया सामग्री-प्रकार सेट करने के लिए किया जाता है। यदि आपको किसी विशेष कंट्रोलर विधि के लिए सिर्फ रिपॉइंट कंटेंट टाइप सेट करने की आवश्यकता है, तो इसके बजाय वारियर के उत्तर का उपयोग करें (उपयोग
@RequestMapping

3
@GiulioPiancastelli आपके पहले प्रश्न को जोड़कर हल किया जा सकता है <संपत्ति का नाम = "writeAcceptCharset" मान = "झूठी" /> बीन के लिए
PickBoy

44

बस मामले में आप निम्नलिखित तरीके से एन्कोडिंग सेट कर सकते हैं:

@RequestMapping(value = "ajax/gethelp")
public ResponseEntity<String> handleGetHelp(Locale loc, String code, HttpServletResponse response) {
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.add("Content-Type", "text/html; charset=utf-8");

    log.debug("Getting help for code: " + code);
    String help = messageSource.getMessage(code, null, loc);
    log.debug("Help is: " + help);

    return new ResponseEntity<String>("returning: " + help, responseHeaders, HttpStatus.CREATED);
}

मुझे लगता है कि StringHttpMessageConverter का उपयोग करना इस से बेहतर है।


यह भी समाधान है यदि आप the manifest may not be valid or the file could not be opened.IE 11 में त्रुटि प्राप्त करते हैं । धन्यवाद digz!
अरुण क्रिस्टोफर

21

आप RequestMapping में = "text / plain; charset = UTF-8" जोड़ सकते हैं

@RequestMapping(value = "/rest/create/document", produces = "text/plain;charset=UTF-8")
@ResponseBody
public String create(Document document, HttpServletRespone respone) throws UnsupportedEncodingException {

    Document newDocument = DocumentService.create(Document);

    return jsonSerializer.serialize(newDocument);
}

अधिक विस्तार के लिए इस ब्लॉग को देखें


2
यह कोड संकलित नहीं होगा; आप एक शून्य विधि से कुछ वापस कर रहे हैं।
एंड्रयू स्वान

2
माफ करना, बुरा बग अब यह तय हो गया है
चार्ली वू

3
यह गलत उत्तर है। स्प्रिंग डॉक्स के अनुसार: प्राथमिक मैपिंग को सीमित करते हुए मैप किए गए अनुरोध के विलक्षण मीडिया प्रकार। प्रारूप मीडिया प्रकारों ("टेक्स्ट / प्लेन", "एप्लिकेशन / *) का एक अनुक्रम है, केवल एक अनुरोध के साथ अगर मैप इन मीडिया प्रकारों में से एक से मेल खाता है, तो"! "ऑपरेटर, के रूप में उपयोग करके अभिव्यक्तियों को नकारा जा सकता है! "! पाठ / सादा", जो "पाठ / सादे" के अलावा किसी अन्य स्वीकार के साथ सभी अनुरोधों से मेल खाता है।
Oleksandr_DJ

@CharlieWu लिंक के साथ एक समस्या है
मैट

10

मैं हाल ही में इस मुद्दे पर लड़ रहा था और स्प्रिंग 3.1 में उपलब्ध एक बेहतर जवाब पाया।

@RequestMapping(value = "ajax/gethelp", produces = "text/plain")

तो, JAX-RS के रूप में आसान के रूप में सभी टिप्पणियों की तरह यह इंगित किया जा सकता है / होना चाहिए।


वसंत 3.1 के लिए वर्थ पोर्टिंग!
young.fu.panda

5
@dbyoung यह सही नहीं लगता है, के लिए javadoc producesकहते हैं: "... केवल अनुरोध मैप किया जाता है यदि सामग्री-प्रकार इन मीडिया प्रकारों में से एक से मेल खाता है।" जिसका अर्थ है AFAIK जो कि इस बात के producesलिए प्रासंगिक है कि क्या विधि एक अनुरोध से मेल खाती है और यह नहीं कि प्रतिक्रिया किस प्रकार की होनी चाहिए।
इट्टाई

@ इत्ते सही! यदि विधि अनुरोध से मेल खाती है, तो "उत्पादन" निर्धारित करता है, लेकिन प्रतिक्रिया में सामग्री प्रकार क्या नहीं है। कुछ और सामग्री के प्रकार को निर्धारित करते समय "उत्पादन" पर देखना चाहिए
एंटोन 1980

6

आप नियंत्रक से भेजे जाने वाले प्रतिक्रिया के प्रकार को इंगित करने के लिए उत्पादन का उपयोग कर सकते हैं। यह "उत्पादन" कीवर्ड अजाक्स अनुरोध में सबसे उपयोगी होगा और मेरी परियोजना में बहुत मददगार था

@RequestMapping(value = "/aURLMapping.htm", method = RequestMethod.GET, produces = "text/html; charset=utf-8") 

public @ResponseBody String getMobileData() {

}

4

धन्यवाद digz6666, आपका समाधान मेरे लिए थोड़े बदलाव के साथ काम करता है क्योंकि मैं json का उपयोग कर रहा हूं:

responseHeaders.add ("सामग्री-प्रकार", "आवेदन / json; चारसेट = utf-8");

Axtavt द्वारा दिए गए उत्तर (जो आपने सुझाए हैं) मेरे लिए काम नहीं करेंगे। भले ही मैंने सही मीडिया प्रकार जोड़ा हो:

अगर (कनफटेस्टोफ़ स्ट्रींगटेटमेज़ेजकॉनर्टर) {                   
                    ((StringHttpMessageConverter) conv) .setSupportedMediaTypes (
                        Arrays.asList (
                                नया मीडिया टाइप ("टेक्स्ट", "html", चारसेट.फोरनाम ("UTF-8")),
                                नया मीडिया टाइप ("एप्लिकेशन", "जोंस", चारसेट.फोरनाम ("यूटीएफ -8"))));
                }

4

मैं ContentNegotiatingViewResolver सेम में MarshallingView में सामग्री-प्रकार सेट करता हूं । यह आसानी से, साफ और आसानी से काम करता है:

<property name="defaultViews">
  <list>
    <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
      <constructor-arg>
        <bean class="org.springframework.oxm.xstream.XStreamMarshaller" />     
      </constructor-arg>
      <property name="contentType" value="application/xml;charset=UTF-8" />
    </bean>
  </list>
</property>

3

मैं CharacterEncodingFilter का उपयोग कर रहा हूं, web.xml में कॉन्फ़िगर किया गया है। शायद यही मदद करता है।

    <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

1
यह सिर्फ अनुरोध में चरित्र फिल्टर, जवाब में नहीं - मैं allready इस एक का उपयोग कर रहा
हुर्दा

@ हुरडा: इसके साथ forceEncoding=trueप्रतिक्रिया को भी फ़िल्टर करता है, लेकिन यह इस मामले में मदद नहीं करेगा।
axtavt

अब तक का सर्वश्रेष्ठ और तेज उत्तर। मैं पहले से ही इस फिल्टर को घोषित और उपयोग कर रहा था, लेकिन साथ forceEncoding=false। मैंने अभी इसे सेट किया है falseऔर "charset = UTF-8" को Content-Typeहेडर में सफलतापूर्वक जोड़ा गया है ।
साद बेनबोज़िद

2

यदि उपरोक्त में से किसी ने भी आपके लिए "POST" नहीं "GET" पर ajax अनुरोध करने की कोशिश की, जो मेरे लिए अच्छी तरह से काम किया ... उपरोक्त में से कोई भी नहीं किया। मैं भी चरित्र है। कोडिंग।


2
package com.your.package.spring.fix;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * @author Szilard_Jakab (JaKi)
 * Workaround for Spring 3 @ResponseBody issue - get incorrectly 
   encoded parameters     from the URL (in example @ JSON response)
 * Tested @ Spring 3.0.4
 */
public class RepairWrongUrlParamEncoding {
    private static String restoredParamToOriginal;

    /**
    * @param wrongUrlParam
    * @return Repaired url param (UTF-8 encoded)
    * @throws UnsupportedEncodingException
    */
    public static String repair(String wrongUrlParam) throws 
                                            UnsupportedEncodingException {
    /* First step: encode the incorrectly converted UTF-8 strings back to 
                  the original URL format
    */
    restoredParamToOriginal = URLEncoder.encode(wrongUrlParam, "ISO-8859-1");

    /* Second step: decode to UTF-8 again from the original one
    */
    return URLDecoder.decode(restoredParamToOriginal, "UTF-8");
    }
}

के बाद मैंने इस मुद्दे के लिए बहुत सारे समाधान की कोशिश की है .. मैंने सोचा कि यह ठीक है और यह ठीक काम करता है।


2

स्प्रिंग 3.1.1 में इस समस्या को हल करने का सरल तरीका यह है कि निम्नलिखित कॉन्फ़िगरेशन कोड जोड़ें servlet-context.xml

    <annotation-driven>
    <message-converters register-defaults="true">
    <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter">
    <beans:property name="supportedMediaTypes">    
    <beans:value>text/plain;charset=UTF-8</beans:value>
    </beans:property>
    </beans:bean>
    </message-converters>
    </annotation-driven>

कुछ भी ओवरराइड या कार्यान्वित करने की आवश्यकता नहीं है।


2

यदि आप निम्न कॉन्फ़िगरेशन के माध्यम से इस समस्या को ठीक करने का निर्णय लेते हैं:

<mvc:annotation-driven>
  <mvc:message-converters register-defaults="true">
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
      <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
    </bean>
  </mvc:message-converters>
</mvc:annotation-driven>

आपको पुष्टि करनी चाहिए कि आपकी सभी * .xml फ़ाइल में केवल एक mvc: एनोटेशन-संचालित टैग होना चाहिए। अन्यथा, कॉन्फ़िगरेशन प्रभावी नहीं हो सकता है।


1

लिंक के अनुसार "यदि एक वर्ण एन्कोडिंग निर्दिष्ट नहीं है, तो सर्वलेट विनिर्देशन के लिए आवश्यक है कि ISO-88599 का एन्कोडिंग का उपयोग किया जाए"। यदि आप स्प्रिंग 3.1 का उपयोग कर रहे हैं या बाद में चार्जसेट सेट करने के लिए फॉलिंग कॉन्फ़िगरेशन का उपयोग करते हैं = UTF-8 प्रतिक्रिया निकाय
@RequestMapping (मान = "आपका मानचित्रण url", = "पाठ / सादा; चारसेट = UTF-8") का उत्पादन करता है


0
public final class ConfigurableStringHttpMessageConverter extends AbstractHttpMessageConverter<String> {

    private Charset defaultCharset;

    public Charset getDefaultCharset() {
        return defaultCharset;
    }

    private final List<Charset> availableCharsets;

    private boolean writeAcceptCharset = true;

    public ConfigurableStringHttpMessageConverter() {
        super(new MediaType("text", "plain", StringHttpMessageConverter.DEFAULT_CHARSET), MediaType.ALL);
        defaultCharset = StringHttpMessageConverter.DEFAULT_CHARSET;
        this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
    }

    public ConfigurableStringHttpMessageConverter(String charsetName) {
        super(new MediaType("text", "plain", Charset.forName(charsetName)), MediaType.ALL);
        defaultCharset = Charset.forName(charsetName);
        this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
    }

    /**
     * Indicates whether the {@code Accept-Charset} should be written to any outgoing request.
     * <p>Default is {@code true}.
     */
    public void setWriteAcceptCharset(boolean writeAcceptCharset) {
        this.writeAcceptCharset = writeAcceptCharset;
    }

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

    @Override
    protected String readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
        Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
        return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
    }

    @Override
    protected Long getContentLength(String s, MediaType contentType) {
        Charset charset = getContentTypeCharset(contentType);
        try {
            return (long) s.getBytes(charset.name()).length;
        }
        catch (UnsupportedEncodingException ex) {
            // should not occur
            throw new InternalError(ex.getMessage());
        }
    }

    @Override
    protected void writeInternal(String s, HttpOutputMessage outputMessage) throws IOException {
        if (writeAcceptCharset) {
            outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
        }
        Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
        FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
    }

    /**
     * Return the list of supported {@link Charset}.
     *
     * <p>By default, returns {@link Charset#availableCharsets()}. Can be overridden in subclasses.
     *
     * @return the list of accepted charsets
     */
    protected List<Charset> getAcceptedCharsets() {
        return this.availableCharsets;
    }

    private Charset getContentTypeCharset(MediaType contentType) {
        if (contentType != null && contentType.getCharSet() != null) {
            return contentType.getCharSet();
        }
        else {
            return defaultCharset;
        }
    }
}

नमूना विन्यास:

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <util:list>
                <bean class="ru.dz.mvk.util.ConfigurableStringHttpMessageConverter">
                    <constructor-arg index="0" value="UTF-8"/>
                </bean>
            </util:list>
        </property>
    </bean>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.