web-dev-qa-db-fra.com

Qui définit le type de contenu de la réponse dans Spring MVC (@ResponseBody)

J'ai une application Web Spring MVC Java exécutée sur des annotations exécutée sur un serveur Web Jetty (actuellement dans le plug-in Maven Jetty).

J'essaie de prendre en charge AJAX avec une méthode de contrôleur renvoyant uniquement le texte d'aide String. Les ressources sont encodées en UTF-8, de même que la chaîne, mais ma réponse du serveur est livrée avec

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

même quand mon navigateur envoie

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

J'utilise en quelque sorte la configuration par défaut du ressort

J'ai trouvé un indice pour ajouter ce bean à la configuration, mais je pense qu'il n'est tout simplement pas utilisé, car il indique qu'il ne prend pas en charge le codage et qu'un codage par défaut est utilisé.

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

Mon code de contrôleur est (notez que ce changement de type de réponse ne fonctionne pas pour moi):

@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;
}
119
Hurda

La déclaration simple du bean StringHttpMessageConverter ne suffit pas, vous devez l'injecter dans 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>

Cependant, en utilisant cette méthode, vous devez redéfinir tous les HttpMessageConverters, et cela ne fonctionne pas non plus avec <mvc:annotation-driven />.

Donc, peut-être que la méthode la plus commode mais la plus moche consiste à intercepter l’instanciation de la AnnotationMethodHandlerAdapter avec 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 " />
60
axtavt

J'ai trouvé une solution pour Spring 3.1. avec l'aide de l'annotation @ResponseBody. Voici un exemple de contrôleur utilisant la sortie Json:

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

}
158
Warrior

Notez que dans Spring MVC 3.1, vous pouvez utiliser l'espace de noms MVC pour configurer les convertisseurs de message:

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

Ou configuration basée sur un code:

@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 ...
  }
}
49
Rossen Stoyanchev

Juste au cas où vous pouvez également définir le codage de la manière suivante:

@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);
}

Je pense que l'utilisation de StringHttpMessageConverter est meilleure que cela.

44
digz6666

vous pouvez ajouter des produits = "text/plain; charset = UTF-8" à RequestMapping

@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);
}

voir ce blog pour plus de détails

19
Charlie Wu

Je me suis battu récemment contre ce problème et j'ai trouvé une réponse bien meilleure au printemps 3.1:

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

Aussi simple que JAX-RS, comme tous les commentaires l’indiquent, cela pourrait/devrait être.

10
dbyoung

J'ai défini le type de contenu dans MarshallingView dans le bean ContentNegotiatedViewResolver . Cela fonctionne facilement, propre et en douceur:

<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>
4
Reto-san

Vous pouvez utiliser le produit pour indiquer le type de réponse que vous envoyez depuis le contrôleur. Ce mot clé "produira" sera le plus utile dans la requête ajax et a été très utile dans mon projet

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

public @ResponseBody String getMobileData() {

}

Merci digz6666, votre solution fonctionne pour moi avec de légères modifications car j'utilise json:

 responseHeaders.add ("Content-Type", "application/json; charset = utf-8"); 

La réponse donnée par axtavt (que vous avez recommandée) ne fonctionnera pas pour moi. Même si j'ai ajouté le type de média correct:

 if (conv instance de StringHttpMessageConverter) {
 ((StringHttpMessageConverter) conv) .setSupportedMediaTypes (
 Arrays.asList (
 new MediaType ("text", "text", "html" , Charset.forName ("UTF-8")), 
 Nouveau MediaType ("application", "json", Charset.forName ("UTF-8")))); 
} 
4
redochka

J'utilise CharacterEncodingFilter, configuré dans le fichier web.xml. Peut-être que ça aide.

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

si vous décidez de résoudre ce problème via la configuration suivante:

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

vous devez confirmer qu’il ne devrait y avoir qu’une seule balise mvc: annotation dans l’ensemble de votre fichier * .xml. sinon, la configuration risque de ne pas être efficace.

2
Lich
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");
    }
}

Après avoir essayé beaucoup de solution de contournement pour ce problème .. J'ai réfléchi à la question et tout fonctionne bien.

2
Szilard Jakab

Le moyen le plus simple de résoudre ce problème dans Spring 3.1.1 consiste à: ajouter les codes de configuration suivants dans 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>

Vous n'avez pas besoin de modifier ou d'implémenter quoi que ce soit.

2
AdaroMu

si rien de ce qui précède n'a fonctionné pour vous, essayez de faire des requêtes ajax sur "POST" et non "GET", cela a bien fonctionné pour moi ... rien de ce qui précède ne l'a été. J'ai aussi le caractèreEncodingFilter.

2
Marius

Selon lien "Si aucun codage de caractères n'est spécifié, la spécification Servlet requiert l'utilisation d'un codage ISO-8859-1". Si vous utilisez Spring 3.1 ou une version ultérieure, utilisez la configuration suivante pour: définir charset = UTF-8 sur le corps de la réponse
@ RequestMapping (valeur = "votre URL de mappage", produit = "text/plain; charset = UTF-8")

1
Ramesh Papaganti
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;
        }
    }
}

Exemple de configuration:

    <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>
0
Igor Kostomin